Translate this page
Controlling The Real World With Computers
::. Control And Embedded Systems .::


Experiment 11 - Using Analog Inputs For Bi-Dirctional Control Of Motors
Home                                                        Order Let me know what you think
Previous: Experiment 10 - Using Analog Inputs To Control Motors

This experiment shows how to use analog to control a PWM channel bi-directionally. The TIP120 darlington transistor (see TIP120.PDF) will be used here in a manner very similar to the way it was used in Experiment 10.

Bi-Directional Pulse Width Modulation Control Of Motors

The TO-220 package of the TIP120 is shown again below. Remember that the tab is connected to the collectors of the transistors, so if the heat sink is grounded the tab must be insulated from the heat sink but still conduct heat to it.

Bi-Directional Pulse Width Modulation Control Of Motors

A relay will be used to control the direction of the motor. The basic mechanical relay is an electromagnet that attracts one or more pole pieces when turned on. Each pole piece (usually shortened to the word "pole") is associated with one or more throw positions. Together they act as a switch.

The electromagnet is usually shown as a coil with the poles and throws above it. The poles are considered to be up and connected to the top throw positions when the magnet is off. The poles are considered to be pulled down when the magnet is turned on, connecting the poles to the lower throw positions. Thus, the upper throw positions are considered normally closed (NC) and the lower throw positions are considered normally opened (NO). A double pole double throw (DPDT) relay is shown schematically below:

Bi-Directional Pulse Width Modulation Control Of Motors

The wiring of the motor, the TIP120, and the PPI is shown below as it was in Experiment 10, but with the addition of a relay for controlling direction. Two 1N4747A 20 volt zeners (see Experiment 4 for more on zeners) connected back-to-back protect the relay contacts from high voltage motor spikes of either polarity:

Bi-Directional Pulse Width Modulation Control Of Motors

The poles are up and connected to their normally closed positions when the relay's electromagnet is off. A close study of the diagram will show that this condition connects 5 volts to the bottom of the motor and the collectors of the TIP120 to the top of the motor. The opposite is true when the relay is turned on; the top of the motor connects to 5 volts and the bottom to the TIP120. The reversal changes the direction of the motor.

The relay's pins connect as follows. Notice the greater distance between the coil pins and the others:

Bi-Directional Pulse Width Modulation Control Of Motors

The relay fits in the same space as a 16-pin IC. The above view is from the bottom, but the symmetry lines everything up from the top in basically the same manner. The numbering of the pins is kept the same as an IC even though some of the positions are not used. The poles are pins 4 and 13. They connect to the motor and the zeners. Connect 6 and 9 together, and 8 and 11 together. Connect 6 to either the 5 volt supply or to the collectors of the TIP120. Connect 8 to the place you didn't connect 6 to.

The relay will be driven with a PN2222 transistor:

Bi-Directional Pulse Width Modulation Control Of Motors

The coil resistance of the relay I used is 125 ohms. It operates on 5 volts. Thus, from How To Read A Schematic, the current is 5/125 = .04 AMPS or 40ma. A transistor will be used to amplify the current from the 82C55 in order to control the relay.

The PN2222 transistor has a current gain (hfe) of at least 35 (see Experiment 4 for a definition of hfe). The hfe chart can be found on page 2 of PN2222.PDF. The 82C55 will provide 3 volts and 2.5ma of current (see the Electrical Specifications chart on page 17 of 82C55.PDF).

Recall from Experiment 4 that there is about .7 volts from the base to ground. If we use a 1K ohm resistor from the 82C55 to the base of the PN2222, the current will be
I = (3 - .7)/1000 = 2.3ma (see How To Read A Schematic).

The 1K to ground keeps down noise. Its current is .7/1000 = 700 microamps (millionths of an amp). This must be subtracted from the input current providing a net output current of
(((3 - .7)/1000) - (.7/1000)) * 35 = 56ma
(values in schematic)

The 82C55 will easily deliver the required current which will be amplified by a factor of 35, giving us 56ma, which is more than enough to drive the relay.

From TIP120.PDF it is found that the TIP120 has an hfe of 1000. If it is desired to drive a 1 AMP load, an input of 1/1000 = 1ma is needed. Recall from the schematic above that the emitter output of the first transistor is connected to the base of the second. The gain is the product of the gains of the two transistors. The base to emitter drop is now doubled to 1.4 V. That means we need an input resistor of
(3 - 1.4)/1ma = 1600 ohms

Another way to design the circuit is to provide the maximum available drive. The 82C55 can supply 2.5ma, so
(3 - 1.4)/2.5ma = 640 ohms

Since only 1ma is needed, let's go for about half of maximum and use 1200 ohms which is a standard value. This gives us
(3 - 1.4)/1200 = 1.333333ma

It's a good idea to have a resistor from base to ground to cut down on noise. We have .333333ma left to still give us 1ma drive current. Since there is 1.4 volts from base to emitter, the value of the resistor would be
1.4/.333333ma

A close standard value is 4.7K. We now have a net output current from the TIP120 of
(((3 - 1.4)/1200) - (1.4/4700)) * 1000 = 1.035460993 AMPS

If you want to go for maximum drive, try the standard 680 ohms value (always go high on this one). Now the current required of the 82C55 is
(3 - 1.4)/680 = 2.352941ma

That leaves 2.5 - 2.352941 = .147059ma for the noise suppression resistor. So,
1.4/.147059ma = 9519.988576

The closest standard value is 10K. The net drive current is now
((3 - 1.4/680) - (1.4/10000)) * 1000 = 2.212941176 AMPS
(values in schematic)

NOTE: Please be sure to read the Warranty And Disclaimer before working with the hardware!

The output control header module has been changed to modify the structure for setting up an analog channel:

  // outct11a.h

  .........

  struct anachan
  {
    int status;
    int last_value;
    int current_value;
    int controls_PWM;
    int PWM_channel;
    int PWM_Direction_Channel;
    int arraynumber;
    int NoiseBand;
  };
  .........

  // end outct11a.h

The only element that has been added that is different from Experiment 10 is PWM_Direction_Channel. It has been added to provide a port number for controlling direction.

The following shows the changes to TurnOnAnalog(..) in the timer header and C modules:

  // timer11a.h

  .........

int TurnOnAnalog(int channel, // analog channel number
                 int type, // 0=no digital control, 1=forward, 2=bi-directional
                 int arraynumber, // output control array number
                 int PWMPortNumber, // port bit for forward control
                 int PWMDirectionPort, // port bit for direction control
                 int NoiseBand); // current and last reading must differ by
                                 // this much for PWM change to take place

  .........

  // end timer11a.h

// timer11a.c

.........

int TurnOnAnalog(int channel, // analog channel number
                 int type, // 0=no digital control, 1=forward, 2=bi-directional
                 int arraynumber, // output control array number
                 int PWMPortNumber, // port bit for forward control
                 int PWMDirectionPort, // port bit for direction control
                 int NoiseBand) // current and last reading must differ by
                                // this much for PWM change to take place
{
  if(channel < 0 || channel > 7)
    return -1;

  AnnalogChannel[channel].status = START_CONVERSION;

  if(type)
  {
    AnnalogChannel[channel].controls_PWM = type;
    AnnalogChannel[channel].PWM_channel = PWMPortNumber;
    AnnalogChannel[channel].PWM_Direction_Channel = PWMDirectionPort;
    AnnalogChannel[channel].arraynumber = arraynumber;
    AnnalogChannel[channel].NoiseBand = NoiseBand;
    AnnalogChannel[channel].last_value = 0;
  }

  DA_Enabled = 1;

  return channel;
}

.........

// end timer11a.c

Some changes have been made to pwm(..) and PwmAndDirectionDuty(..) in the timer C module. The pwm(..) routine now simply turns the output off if any of the times are out of range. It also now handles the type 2 mode; the one used in this experiment. PwmAndDirectionDuty(..) is sped up a little when the forward and reverse duty cycles are the same as they would be in the case where a direction line is used:

// timer11a.c

.........

// Set up Pulse Width Modulation for an output
//
// arraynumber is the position in the output control array
//
// type:
// 0 = unidirectional, no brake
// 1 = unidirectional with brake
// 2 = pwm line, directional line, no brake
// 3 = pwm line, directional line, with brake
// 4 = dual pwm lines -- both high = brake
// 5 = pwm line and two direction lines as for L298
// 255 = last slot -- leave
//
// Forward and Reverse port numbers are pwm lines for each
//
// The Direction port number is provided for bridges that have a reverse line
// Set to anything if not used
//
// The Brake port number is provided for circuits that have a brake line
// Set to anything if not used
//
int pwm(int arraynumber, int type,
    int ForwardPortNumber, int ReversePortNumber,
    int DirectionPortNumber, int BrakePortNumber,
    double ForwardOnTime, double ForwardOffTime,
    double ReverseOnTime, double ReverseOffTime,
    int StartDirection)
{
  if(StartDirection < 0 || StartDirection > 2)
      return 0;

  if(ForwardOnTime < MinTime || ForwardOnTime > MaxTime
  	|| ForwardOffTime < MinTime || ForwardOffTime > MaxTime
  	|| ReverseOnTime < MinTime || ReverseOnTime > MaxTime
  	|| ReverseOffTime < MinTime || ReverseOffTime > MaxTime)
  {
    puts("in pwm() forward or reverse on or off too low or too high\nso turning off if activated");

    printf("since MinTime = %f MaxTime = %f\n",MinTime,MaxTime);

    printf("and ForwardOnTime = %f ForwardOffTime = %f\n"
    ,ForwardOnTime,ForwardOffTime);

    printf("and ReverseOnTime = %f ReverseOffTime = %f\n"
    ,ReverseOnTime,ReverseOffTime);

    if(NULL != OutputControl[arraynumber])
    {
      // turn off forward bit
      *OutputControl[arraynumber]->ForwardPortData
        &= OutputControl[arraynumber]->ForwardOffMask;

      // put the result in this node's port register
      outp(OutputControl[arraynumber]->ForwardPortAddress,
        *OutputControl[arraynumber]->ForwardPortData);

      OutputControl[arraynumber]->ForwardOnCount = 0L;
      OutputControl[arraynumber]->ForwardOffCount = 0L;
      OutputControl[arraynumber]->ForwardSetOn = 0L;
      OutputControl[arraynumber]->ForwardSetOff = 0L;

      // turn off reverse bit
      *OutputControl[arraynumber]->ReversePortData
        &= OutputControl[arraynumber]->ReverseOffMask;

      // put the result in this node's port register
      outp(OutputControl[arraynumber]->ReversePortAddress,
        *OutputControl[arraynumber]->ReversePortData);

      OutputControl[arraynumber]->ReverseOnCount = 0L;
      OutputControl[arraynumber]->ReverseOffCount = 0L;
      OutputControl[arraynumber]->ReverseSetOn = 0L;
      OutputControl[arraynumber]->ReverseSetOff = 0L;

    } // end if(NULL != OutputControl[arraynumber])

    else printf("arraynumber %d not activated\n",arraynumber);

    return 1;

  } // end if(ForwardOnTime < MinTime || ForwardOnTime > MaxTime

  disable(); // no interrupts while setting up

  if(!ConfigureOutput(arraynumber, type,
                      ForwardPortNumber,
                      ReversePortNumber,
                      DirectionPortNumber,
                      BrakePortNumber))
  {
    enable();
    puts("in pwm() bad ConfigureOutput");
    return 0;
  }

  OutputControlActive = 1;

  OutputControl[arraynumber]->ForwardSetOn =
    (long)((frequency * ForwardOnTime) + 0.5); // round up at .5

  OutputControl[arraynumber]->ForwardSetOff
    = (long)((frequency * ForwardOffTime) + 0.5);

  OutputControl[arraynumber]->ForwardOnCount
    = OutputControl[arraynumber]->ForwardSetOn;

  OutputControl[arraynumber]->ForwardOffCount
    = OutputControl[arraynumber]->ForwardSetOff;

  OutputControl[arraynumber]->direction = StartDirection;

  OutputControl[arraynumber]->type = type;

  printf("in pwm() array = %d type = %d Direction = %d\nForwardOnTime = %f ForwardOffTime = %f\n"
  ,arraynumber,type,StartDirection,ForwardOnTime,ForwardOffTime);

  printf("in pwm() ForwardSetOn = %ld ForwardSetOff = %ld\n"
  ,OutputControl[arraynumber]->ForwardSetOn
  ,OutputControl[arraynumber]->ForwardSetOff);

  if(!type) // uni directional
  {
    enable();
    return 1;
  }

  if(type == 1 || type == 3) // 1 and 3 have a brake
  {
    *OutputControl[arraynumber]->BrakePortData
      &= OutputControl[arraynumber]->BrakeOffMask; // turn off the brake

    outp(OutputControl[arraynumber]->BrakePortAddress,
      *OutputControl[arraynumber]->BrakePortData);
  }

  if(type > 1) // 2,3,4,5 use reverse pwm line, 2,3,5 use direction line
  {
    if(ReverseOnTime < MinTime || ReverseOnTime > MaxTime
    	|| ReverseOffTime < MinTime || ReverseOffTime > MaxTime)
    {
      free(OutputControl[arraynumber]);
      OutputControl[arraynumber] = NULL;
      enable();
      puts("in pwm() bad reverse on or off");
      return 0;
    }

    OutputControl[arraynumber]->ReverseSetOn =
      (long)((frequency * ReverseOnTime) + 0.5); // round up at .5

    OutputControl[arraynumber]->ReverseOnCount
      = OutputControl[arraynumber]->ReverseSetOn;

    OutputControl[arraynumber]->ReverseSetOff =
      (long)((frequency * ReverseOffTime) + 0.5);

    OutputControl[arraynumber]->ReverseOffCount
      = OutputControl[arraynumber]->ReverseSetOff;

    if(type == 2 || type == 3 || type == 5) // 2,3,5 use a direction line
    {
      if(StartDirection == 1)
      *OutputControl[arraynumber]->DirectionPortData
        |= OutputControl[arraynumber]->DirectionOnMask; // set for forward

      else if(StartDirection == 2)
      *OutputControl[arraynumber]->DirectionPortData
        &= OutputControl[arraynumber]->DirectionOffMask; // clear for reverse

      outp(OutputControl[arraynumber]->DirectionPortAddress,
        *OutputControl[arraynumber]->DirectionPortData);

      if(type == 5)
      {
        if(StartDirection == 1)
          *OutputControl[arraynumber]->BrakePortData
            &= OutputControl[arraynumber]->BrakeOffMask; // turn off the brake

        else if(StartDirection == 2)
          *OutputControl[arraynumber]->BrakePortData
            |= OutputControl[arraynumber]->BrakeOnMask; // turn on the brake

        outp(OutputControl[arraynumber]->BrakePortAddress,
          *OutputControl[arraynumber]->BrakePortData);
      }
    }

  } // end if(type > 1)

  enable();

  return 1;

} // end int pwm(..)

// set up a channel with a pwm line and a direction
// line -- no brake using duty cycle
int PwmAndDirectionDuty(int arraynumber, int StartDirection,
                        int PwmPortNumber,
                        int DirectionPortNumber,
                        double ForwardDutycycle,
                        double ReverseDutycycle)
{
  int ret;
  double maxpulse = minpulse * 2.0;
  double ForwardOnTime,ForwardOffTime;
  double ReverseOnTime,ReverseOffTime;

  printf("in PwmAndDirectionDuty forward duty = %f reverse = %f\nminpulse = %f maxpulse = %f\n"
  ,ForwardDutycycle,ReverseDutycycle,minpulse,maxpulse);

  if(ForwardDutycycle > 1.0)
    ForwardDutycycle/=100.0;

  if(ForwardDutycycle > 1.0)
    ForwardDutycycle = 1.0;

  ForwardOnTime = ForwardDutycycle * maxpulse;
  ForwardOffTime = (1.0 - ForwardDutycycle) * maxpulse;

  if(ReverseDutycycle == ForwardDutycycle)
  {
    ReverseOnTime = ForwardOnTime;
    ReverseOffTime = ForwardOffTime;
  }

  else
  {
    if(ReverseDutycycle > 1.0)
      ReverseDutycycle/=100.0;

    if(ReverseDutycycle > 1.0)
      ReverseDutycycle = 1.0;

    ReverseOnTime = ReverseDutycycle * maxpulse;
    ReverseOffTime = (1.0 - ReverseDutycycle) * maxpulse;
  }

  printf("ForwardOnTime = %f ForwardOffTime = %f\n"
  ,ForwardOnTime,ForwardOffTime);

  printf("ReverseOnTime = %f ReverseOffTime = %f\n"
  ,ReverseOnTime,ReverseOffTime);

  ret = pwm(arraynumber, 2, // type 2 = pwm, direction, no brake
    PwmPortNumber, PwmPortNumber, // forward and reverse are same
    DirectionPortNumber, 0, // no brake
    ForwardOnTime, ForwardOffTime,
    ReverseOnTime, ReverseOffTime,
    StartDirection);

  printf("PwmAndDirectionDuty returning %d\n======\n",ret);

  return ret;
}

.............

// timer11a.c

The ConfigureOutput(..) output routine in the digital module has also been changed to handle type 2:


..........

// digi11a.c

#include "digi11a.h"

// configure the array number location with the port numbers indicated
// and to the bit numbers dictated by the port numbers
// type:
// 0 = unidirctional, no brake
// 1 = unidirectional with brake
// 2 = pwm line, directional line, no brake
// 3 = pwm line, directional line, with brake
// 4 = dual pwm lines -- both high = brake
// 5 = pwm line and two direction lines as for L298
// 255 = end of points = tells isr not to look anymore & saves time
int ConfigureOutput(int arraynumber,
                    int type,
                    int ForwardPortNumber,
                    int ReversePortNumber,
                    int DirectionPortNumber,
                    int BrakePortNumber)
{
  int x;

//  printf("in ConfigureOutput() line 23 digi10a, arraynumber = %d\n"
//  ,arraynumber);

  if(arraynumber < 0 || arraynumber > 23)
    return 0; // illegal number

  if(ForwardPortNumber < 0 || ForwardPortNumber > 23)
    return 0; // illegal number

  if(OutputControl[arraynumber] == NULL)
  {
    if((OutputControl[arraynumber] = malloc(sizeof(struct OC))) == NULL)
    {
      printf("Not enough memory for output control.\n");
      return 0;
    }
  }

  // zero out members
  memset(OutputControl[arraynumber], 0, sizeof(struct OC));

  if(type == 255)
  {
    OutputControl[arraynumber]->type = 255; // last
    return 1;
  }

	// set up the forward masks
  if(!SetPort(arraynumber, ForwardPortNumber,
              &OutputControl[arraynumber]->ForwardPortAddress,
              &OutputControl[arraynumber]->ForwardPortData,
              &OutputControl[arraynumber]->ForwardOnMask,
              &OutputControl[arraynumber]->ForwardOffMask))
    return 0;

  if(!type) // unidirectional no brake has forward pwm only
    return 1;

  if(type == 1 || type == 3 || type == 5) // 1,3 and 5 use a brake line
                                          // (5 uses it for logic lines)
  {
    if(!SetPort(arraynumber, BrakePortNumber,
                &OutputControl[arraynumber]->BrakePortAddress,
                &OutputControl[arraynumber]->BrakePortData,
                &OutputControl[arraynumber]->BrakeOnMask,
                &OutputControl[arraynumber]->BrakeOffMask))
      return 0;
  }

  if(type == 1
    || type == 2
    || type == 3
    || type == 5) // 1,2,3 and 5 use a direction line
                  // (5 uses it for logic lines)
  {
    if(!SetPort(arraynumber, DirectionPortNumber,
                &OutputControl[arraynumber]->DirectionPortAddress,
                &OutputControl[arraynumber]->DirectionPortData,
                &OutputControl[arraynumber]->DirectionOnMask,
                &OutputControl[arraynumber]->DirectionOffMask))
      return 0;

    OutputControl[arraynumber]->ReversePortAddress = // reverse is same as forward
      OutputControl[arraynumber]->ForwardPortAddress; // with a direction line

    OutputControl[arraynumber]->ReversePortData =
      OutputControl[arraynumber]->ForwardPortData;

    OutputControl[arraynumber]->ReverseOnMask =
      OutputControl[arraynumber]->ForwardOnMask;

    OutputControl[arraynumber]->ReverseOffMask =
      OutputControl[arraynumber]->ForwardOffMask;

    printf("type = %d, DirectionOnMask = %X, DirectionOffMask = %X\n"
      ,type,OutputControl[arraynumber]->DirectionOnMask
      ,OutputControl[arraynumber]->DirectionOffMask);
  }

  if(type == 4) // 4 is a dual pwm so has a separate reverse line
  {
    if(!SetPort(arraynumber, ReversePortNumber,
                &OutputControl[arraynumber]->ReversePortAddress,
                &OutputControl[arraynumber]->ReversePortData,
                &OutputControl[arraynumber]->ReverseOnMask,
                &OutputControl[arraynumber]->ReverseOffMask))
      return 0;
  }

  return 1;
}

..........

// end digi11a.c

Several print lines are included in all of the modules for debugging purposes. Rem them out if you don't want to see all of the status printing.

To test the procedures, run the following and vary the offset control:

// exper11a.c

// exper11a.c

#include "exper11a.h"

int CheckAnalog(int analog_channel);

enum
{
  MainMotor,
  LED1,
  LED2,
  LASTSLOT
};

void main(void)
{
  int x;
  double dc,oldfreq,newfreq;

  oldfreq = 1193180.0/65536.0;

  printf("oldfreq = %f calling set_up_new_timer for 1K Hz\n",oldfreq);

  set_up_new_timer(1000.0);

  newfreq = get_frequency();

  printf("new frequency = %fHz\n",newfreq);

  x = (int)InitializeAnalog();

  printf("init ana = %X\n",x);

  // make everthing an output
  set_up_ppi(Aout_CUout_Bout_CLout);

  x = TurnOnAnalog(0, // analog channel number
                   2, // 0 = no digital control, 1 = uni-directional, 2 = bi-directional
                   MainMotor, // output control array number
                   PA0, // port bit for forward control
                   PA3, // port bit for direction control
                   6); // current and last reading must differ by
                       // this much for PWM change to take place

  Blink(LED1,PA1, .03, .02);

  Blink(LED2,PA2, .3, .2);

  printf("Blinking LED1=PA1=%d .03,.02; LED2=PA2=%d .3,.2\n",PA1,PA2);
  printf("TurnOnAnalog(PWM=PA0=%d, Direction=PA3=%d) = %d\n",PA0,PA3,x);
  printf("Press any key to continue then any key to quit -- no Ctr-C!\n");

  getch();

  while(!kbhit())
  {
    if(!CheckAnalog(0))
    	break;
  }

  portaoff();

  // be sure to restore the timer!
  restore_old_timer();

  portaoff();
}

int CheckAnalog(int anachan)
{
  int SpeedValue,SetDirection;

  if(abs(AnalogChannel[anachan].current_value -
         AnalogChannel[anachan].last_value) >
         AnalogChannel[anachan].NoiseBand)
    {
      AnalogChannel[anachan].last_value =
        AnalogChannel[anachan].current_value;

      switch(AnalogChannel[anachan].controls_PWM)
      {
        case 1: // unidirectional

        UniPwmDuty(AnalogChannel[anachan].arraynumber,
                   AnalogChannel[anachan].PWM_channel,
                  (double)AnalogChannel[anachan].current_value/255.0);
        break;

        case 2: // bidirectional

        SpeedValue = AnalogChannel[anachan].current_value;

        // the low end of the values, from 0 to 127, are used for reverse
        // the high end values, from 128 to 255, are used for forward

        // for forward, the range is changed from 128 to 255 to 0 to 127

        // for reverse, the range is flipped from 0 to 127 to 127 to 0 so
        // that the low end of the trimmer produces maximum reverse speed

        // the process ends up with 0 to 127 for both forward and reverse,
        // with direction set by the SetDirection variable

        if(SpeedValue > 127) // forward
        {
          SpeedValue-=128; // modify to 0 to 127
          SetDirection = 1; // forward
        }

        else // reverse
        {
          SpeedValue = 127 - SpeedValue; // modify to 127 to 0
          SetDirection = 2; // reverse
        }

        printf("AnalogChannel[%d] changed, now = %d, direction = %d\n"
         ,anachan,AnalogChannel[anachan].last_value,SetDirection);

        printf("SpeedValue = %d /127 = %f\n"
        ,SpeedValue,(double)SpeedValue/127.0);

        printf("AnalogChannel[anachan=%d].PWM_channel = %d\n"
        ,anachan,AnalogChannel[anachan].PWM_channel);

        printf("AnalogChannel[%d].PWM_Direction_Channel = %d\n"
        ,anachan,AnalogChannel[anachan].PWM_Direction_Channel);

        return PwmAndDirectionDuty(AnalogChannel[anachan].arraynumber,
                  SetDirection,
                  AnalogChannel[anachan].PWM_channel,
                  AnalogChannel[anachan].PWM_Direction_Channel,
                  (double)SpeedValue/127.0,
                  (double)SpeedValue/127.0);

        break;

      } // end switch(AnalogChannel[anachan].controls_PWM)

      return 1;

    } // end if(abs(AnalogChannel[anachan].current_value...)
}

// end exper11a.c

If all conditions are met and the controls_PWM element is also set to 2, a call is made to PwmAndDirectionDuty(..) to change the duty cycle of the control channel located at arraynumber using the port designated by PWM_channel, as well as set the direction indicted by SetDirction using PWM_Direction_Channel.

Since the maximum value used for either forward or reverse is 127, the duty cycle is determined by dividing the processed input by 127.

Inputs from the Analog to Digital Converter and their modified values are illustrated below:

Input from Analog to Digital Converter: 0 127 128 255
                  After modification: 127   0   0 127
                                        |   |   |   |_ maximum forward speed
                                        |   |   |_____ minimum forward speed
                                        |   |_________ minimum reverse speed
                                        |_____________ maximum reverse speed

Click here to download timer11a.c
Click here to download timer11a.h
Click here to download exper11a.c
Click here to download exper11a.h
Click here to download extrn11a.h
Click here to download outct11a.h
Click here to download const11a.h
Click here to download digi11a.c
Click here to download digi11a.h
Click here to download digital.h
Click here to download outcont.h

Previous: Experiment 10 - Using Analog Inputs To Control Motors
Problems, comments, ideas? Please Let me know
Copyright © 2003, Joe D. Reeder. All Rights Reserved.