Serial DC motor control using 8051

964 views Asked by At

We are developing the code for the DC motor controller using AT89S51 microcontroller. We use embedded C for code development, Keil microvision as IDE, Progisp for uploading .hex files to microcontroller and PUTTY for serial interfacing.

Here is the code:

#include <reg51.h>
#include <stdio.h>
unsigned int k;
sbit motor = P1^0;

void delay ( int q ) {
  int w;
  for ( w = 0; w < q; w++ );
}

void next_line()
{
  SBUF = 10; // go to next line
  while(TI == 0);
  TI = 0; 
  SBUF = 13; // go to the beginning of the line
  while(TI == 0);
  TI = 0;
}

unsigned char receive() //Function to receive serial data 
{ 
  unsigned char value;
  while ( RI == 0 );
  value=SBUF; 
  P1=value; 
  RI=0;
  return value;
} 

void start()
{
  SCON=0x50;
  TMOD=0x20;
  TH1=0xFD;
  TR1=1;
  TI=1;
}

int i;

main()
{
  while (1)
  {
    unsigned char speed = 0;
    start();
    speed=receive();
    switch (speed)
    {
    case '1':
      k=90; // 90 msec out of 100 msec
      next_line();
      break;
    case '0':
      k=10; // 10 msec out of 100 msec
      next_line();
      break;
    };
    for(i=0; i<100; i++)
    {
      if (i<k) {
        motor = 0;
      }
      else {
        motor = 1;
      }
    }
  }
}

We expect the motor to work on 90% power when the '1' button is pressed and to switch to 10% power when the '0' button is pressed. However, what we see is that some keyboard buttons (1,4,5,8) switch the motor ON and some buttons (2,3,6,7) switch the motor OFF. I cannot understand the nature of the improper working. Please, could you help us with this issue. Thanks in advance

2

There are 2 answers

0
Weather Vane On BEST ANSWER

I am going to hazard a guess as to the problem and risk being downvoted for it. The main loop is only writing to the motor bit for a very short period of time before committing to a read of the serial port, and that motor write leaves a 1 in the control port bit no matter what duty cycle was selected, so the motor should be left either running or stopped. But OP says pressing a key either stops or runs the motor. The receive() function waits for input and then writes it to the motor port (which is not bit-defined) before returning. It's tempting to think that is what is controlling the motor, but the LSB of OP's key presses is not consistent with the motor control. So what is it? The keys that start the motor all have bit 1 clear and the keys that stop the motor all have bit 1 set. So my first guess is that OP has defined the wrong bit for motor control and that the correct declaration is

sbit motor = P1^1;

Then remove this line from the receive() function

P1 = value;

My second guess from bit 1 of the key presses is that the motor logic is inverted so that 0 runs the motor and 1 stops it. On top of that, the main loop should check for serial char input and here is my (untested!) rewrite of main()

main()
{
    unsigned char speed;
    int k = 10;                     // default is 'slow'
    int i;
    start();                        // moved outside of loop
    while (1)                       // repeat until power off
    {
        while (RI == 0)             // repeat until serial data in
        {
            for(i=0; i<100; i++)    // duty cycle
                if (i<k)
                    motor = 1;      // off: or 0x02 if required for b1
                else
                    motor = 0;      // on: I have inverted the logic
        }

        speed=receive();            // get key press
        switch (speed)
        {
            case '1':
                k=90;               // 90 msec out of 100 msec
                next_line();
                break;
            case '0':
                k=10;               // 10 msec out of 100 msec
                next_line();
                break;
        }
    }
}
2
Weather Vane On

Your while loop in main appears to be setting the 1-bit motor control with a 10% or 90% duty cycle, it does this by writing to motor which has been equated to P1. But after 100 writes it calls receive(), and that should leave the motor running, because the function won't return until a key is pressed. So I don't understand why the motor is sometimes stopped. When the function does return, your case statements do not take into account what other key might have been pressed, so you will be simply using k set from the previous key press. In addition, receive() waits for RXD and then writes the character received to P1 the motor control. So on the face of it, the LSB of RXD is being used to control the motor. But that's a bug, because on return from receive() P1 is again written to.