Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Running BLDC motor counter-clockwise

Status
Not open for further replies.

Cantafford

Member
Hello,

I'm trying to run a BLDC motor clockwise in proteus simulator. I wrote a code in MPLAB for PIC18F2431. My motor is running fine in the clockwise direction but I just can't get it to spin in the counter clockwise direction. I wrote this code:

Code:
#include <stdio.h>
#include <stdlib.h>
#include "header.h"
#include <plib/delays.h>
#include <plib/xlcd.h>

#define FCY 6250000

int HALL;
int HALLvalue[6] = { 0b00000001, 0b00000101, 0b00000100, 0b00000110, 0b00000010, 0b00000011 };
int HALLvaluereverse[6] = { 0b00000001, 0b00000011, 0b00000010, 0b00000110, 0b00000100, 0b00000101 };
unsigned int dch;
unsigned int dcl;

float timercount;
float speed, actualspeed;
unsigned char buf[20];
int dir;

float RPMconstant = 60 * 6250000 / 256;
int long timer5;

// Capture Interrupt Service Routine


void init_XLCD(void);       //Initialize LCD display
void DelayFor18TCY( void ); //18 cycles delay
void DelayPORXLCD (void);   // Delay of 15ms
void DelayXLCD (void);       // Delay of 5ms
void CW();
void CCW();
void ConfigureADC();
void CalculateSpeed();
void SetSpeed();
void DisplaySpeed();
void ConfigureInterrupts();
void ConfigureInputCapture();
void ConfigurePCPWM();
void ConfigureTIMER5();
int SelectDir();
void Start();


void interrupt CheckHallValue()
{
  if(IC1IF==1)
  {
   CalculateSpeed();
   SetSpeed();
  }

  IC2QEIF = 0; IC3DRIF = 0;

  if(dir==1) // right sequence
  {
   HALL = (PORTA >> 2) & 0x7; // read the capture pins to get hall sensor state
   CW();
  }

  if(dir==2) // right sequence
  {
   HALL = (PORTA >> 2) & 0x7; // read the capture pins to get hall sensor state
   CCW();
  }

}



void main()
{
 ConfigureADC();
 SCS1 = 0; // use primary
 SCS0 = 0; // oscillator
 TRISA = 0b11111111; // PORTA is input(CAP's + POT)
 TRISB = 0b11000000;
 TRISCbits.RC7 = 0;
 LATCbits.LATC7 = 0; // led initially off

 ConfigureInterrupts();
 ConfigureInputCapture();
 ConfigurePCPWM();
 ConfigureTIMER5();

 init_XLCD();                    //Call the Initialize LCD display function

 //OVDCOND = 0b00100100; // start(needs a change on input capture)
 //PDC2H = 0xFF; PDC2L = 0xFF; PDC1H = 0xFF; PDC1L = 0xFF;
 OVDCONS = 0;

 while(1)
 {
     dir = SelectDir();
     Start();
     ADON = 1;
     DisplaySpeed();
 }

}

void init_XLCD(void)                //Initialize LCD display
{
OpenXLCD(FOUR_BIT&LINES_5X7);       //configure LCD in 4-bit Data Interface mode
                                    //and 5x7 characters, multiple line display
while(BusyXLCD());                  //Check if the LCD controller is not busy
                                    //before writing some commands
WriteCmdXLCD(0x06);                 //Move cursor right, don't shift display
WriteCmdXLCD(0x0C);                 //Turn display on without cursor
}

void DelayFor18TCY( void )         //18 cycles delay
{
Delay10TCYx(20);
}
void DelayPORXLCD (void)           //Delay of 15ms
{
Delay1KTCYx(30);
}
void DelayXLCD (void)              //Delay of 5ms
{
Delay1KTCYx(10);
}

void CW()
{
  if(HALL == HALLvalue[0]) { OVDCOND = 0x09; PDC2H = dch; PDC2L = dcl; PDC1H = dch; PDC1L = dcl; }
  else if(HALL == HALLvalue[1]) { OVDCOND = 0x18; PDC1H = dch; PDC1L = dcl; PDC0H = dch; PDC0L = dcl; }
  else if(HALL == HALLvalue[2]) { OVDCOND = 0x12; PDC2H = dch; PDC2L = dcl; PDC0H = dch; PDC0L = dcl; }
  else if(HALL == HALLvalue[3]) { OVDCOND = 0x06; PDC2H = dch; PDC2L = dcl; PDC1H = dch; PDC1L = dcl; }
  else if(HALL == HALLvalue[4]) { OVDCOND = 0x24; PDC1H = dch; PDC1L = dcl; PDC0H = dch; PDC0L = dcl; }
  else if(HALL == HALLvalue[5]) { OVDCOND = 0x21; PDC2H = dch; PDC2L = dcl; PDC0H = dch; PDC0L = dcl; }
}

void CCW()
{
  if(HALL == HALLvaluereverse[0]) { OVDCOND = 0x06; PDC1H = dch; PDC1L = dcl; PDC0H = dch; PDC0L = dcl; }
  else if(HALL == HALLvaluereverse[1]) { OVDCOND = 0x12; PDC2H = dch; PDC2L = dcl; PDC0H = dch; PDC0L = dcl; }
  else if(HALL == HALLvaluereverse[2]) { OVDCOND = 0x18; PDC2H = dch; PDC2L = dcl; PDC1H = dch; PDC1L = dcl; }
  else if(HALL == HALLvaluereverse[3]) { OVDCOND = 0x09; PDC1H = dch; PDC1L = dcl; PDC0H = dch; PDC0L = dcl; }
  else if(HALL == HALLvaluereverse[4]) { OVDCOND = 0x21; PDC2H = dch; PDC2L = dcl; PDC0H = dch; PDC0L = dcl; }
  else if(HALL == HALLvaluereverse[5]) { OVDCOND = 0x24; PDC2H = dch; PDC2L = dcl; PDC1H = dch; PDC1L = dcl; }
}

void SetSpeed()
{
   while(GODONE); // wait untill conversion is over
   dch = ADRESH >> 2; // set the
   dcl = (ADRESL<<6) | ((ADRESL>>2) & 0x00) ; // duty cycle with the pot
   IC1IF = 0;
   ADON = 0;
}

void CalculateSpeed()
{
   timercount = TMR5;                               // get
   speed = ( 6250000 / (timercount*8*6) ) * 60 / 8.5;     // the
   TMR5 = 0;
   if(dch==0 && dcl==0) {speed = 0; LATCbits.LATC7 = 0; }
}

void DisplaySpeed()
{
    if(dir==0)
    {
     WriteCmdXLCD(0x01); // Clear screen
     putrsXLCD("Select direction");
     while(PORTBbits.RB6==1 && PORTBbits.RB7==1);
     WriteCmdXLCD(0x01); // Clear screen
    }

    if(dir==1)
    {
     putrsXLCD("Dir: CW"); // Display digital on first line
     SetDDRamAddr(0x40); // Shift cursor to beginning of second line
     putrsXLCD("Speed: ");                     //Display on the screen
     sprintf(buf, "%g", speed );        //Convert speed float value to string
     putsXLCD(buf);                             //Display the speed on the screen
     putrsXLCD(" ");                            // Space
     putrsXLCD("RPM");                            // DIsplay RPM
     WriteCmdXLCD(0x02);                        //Home position on LCD
    }

    if(dir==2)
    {
     putrsXLCD("Dir: CCW"); // Display digital on first line
     SetDDRamAddr(0x40); // Shift cursor to beginning of second line
     putrsXLCD("Speed: ");                     //Display on the screen
     sprintf(buf, "%g", speed );        //Convert speed float value to string
     putsXLCD(buf);                             //Display the speed on the screen
     putrsXLCD(" ");                            // Space
     putrsXLCD("RPM");                            // DIsplay RPM
     WriteCmdXLCD(0x02);                        //Home position on LCD
    }


}

void ConfigureADC()
{
  ADCON0 = 0b00000000; // single shot mode, single channel mode
  VCFG1 = 0; // VDD and VSS as ref
  VCFG0 = 0;
  ADCON2 = 0b00001000; // left justified, 2TAD, conversion clock: Fosc/2
  ADCON3 = 0b11000100;  // input capture 1 starts the a/d sequence!!(check here the first two bits)
  GASEL1 = 0; // select AN0
  GASEL0 = 0;
  ANSEL0 = 0b00000001;
}

void ConfigureInterrupts()
{
 GIE = 1; // enable global interrupts
 GIEH = 1;
 PEIE = 1;
}

void ConfigureInputCapture()
{
 // Initialize the Input Capture Module
 CAP1CON = 0b00000000; // disable input capture 1 module
 CAP1CON = 0b00001000; // enable input capture 1 module; interrupt on every state change

 CAP2CON = 0b00000000; // disable input capture 2 module
 CAP2CON = 0b00001000; // enable input capture 2 module; interrupt on every state change

 CAP3CON = 0b00000000; // disable input capture 3 module
 CAP3CON = 0b00001000; // enable input capture 3 module; interrupt on every state change

 // Enable Capture Interrupt and configure TMR5
 IC1IE = 1; // enable IC1 interrupt
 IC1IP = 1; // IC1 interrupt on high priority
 IC1IF = 0; // clear IC1 interrupt status flag

 IC2QEIE = 1; // enable IC2 interrupt
 IC2QEIP = 1; // IC2 interrupt on high priority
 IC2QEIF = 0; // clear IC2 interrupt status flag

 IC3DRIE = 1; // enable IC3 interrupt
 IC3DRIP = 1; // IC3 interrupt on high priority
 IC3DRIF = 0; // clear IC3 interrupt status flag
}

void ConfigurePCPWM()
{
 PTCON0 = 0b00000000; // 1:1 postscale, 1:1 prescale, PWM in free-running mode
 PTCON1 = 0b10000000; // pwm time base is on, the time base counts up
 PWMCON0 = 0b01001111; // pwm0-5 configured as pwm output in independent mode
 SEVOPS3 = 0; // 1:1 postscale
 SEVOPS2 = 0;
 SEVOPS1 = 0;
 SEVOPS0 = 0;
 OSYNC = 1; //Output overrides via the OVDCON register are synchronized to the PWM time base(NOT SURE HERE)

 PTPERH = 0x0F; // frequency is 1.5Khz
 PTPERL = 0xFF; // 0xFF here
}

void ConfigureTIMER5()
{
 T5CON = 0b00011001; // tmr 5 prescaler = 1:8
 PR5H = 0xFF;
 PR5L = 0xFF;
}


int SelectDir()
{
 int answer;
 if(PORTBbits.RB6==1 && PORTBbits.RB7==1) answer = 0; // left
 if(PORTBbits.RB6==0 && PORTBbits.RB7==1) answer = 1; // right
 if(PORTBbits.RB6==1 && PORTBbits.RB7==0) answer = 2; // left
 return answer;
}


void Start()
{
   if(dir==1)
   if(PORTAbits.RA1==0) // start right
   {
    OVDCOND = 0x09;
    PDC2H = 0xFF; PDC2L = 0xFF; PDC1H = 0xFF; PDC1L = 0xFF;
    LATCbits.LATC7 = 1; // turn on LED
   }
   
   if(dir==2)
   if(PORTAbits.RA1==0) // start left
   {
    OVDCOND = 0x06;
    PDC1H = 0xFF; PDC1L = 0xFF; PDC0H = 0xFF; PDC0L = 0xFF;
    LATCbits.LATC7 = 1; // turn on LED
   }

}

These are the routines that are important:

Code:
void CW()
{
  if(HALL == HALLvalue[0]) { OVDCOND = 0x09; PDC2H = dch; PDC2L = dcl; PDC1H = dch; PDC1L = dcl; }
  else if(HALL == HALLvalue[1]) { OVDCOND = 0x18; PDC1H = dch; PDC1L = dcl; PDC0H = dch; PDC0L = dcl; }
  else if(HALL == HALLvalue[2]) { OVDCOND = 0x12; PDC2H = dch; PDC2L = dcl; PDC0H = dch; PDC0L = dcl; }
  else if(HALL == HALLvalue[3]) { OVDCOND = 0x06; PDC2H = dch; PDC2L = dcl; PDC1H = dch; PDC1L = dcl; }
  else if(HALL == HALLvalue[4]) { OVDCOND = 0x24; PDC1H = dch; PDC1L = dcl; PDC0H = dch; PDC0L = dcl; }
  else if(HALL == HALLvalue[5]) { OVDCOND = 0x21; PDC2H = dch; PDC2L = dcl; PDC0H = dch; PDC0L = dcl; }
}

void CCW()
{
  if(HALL == HALLvaluer[0]) { OVDCOND = 0x06; PDC1H = dch; PDC1L = dcl; PDC0H = dch; PDC0L = dcl; }
  else if(HALL == HALLvaluer[1]) { OVDCOND = 0x12; PDC2H = dch; PDC2L = dcl; PDC0H = dch; PDC0L = dcl; }
  else if(HALL == HALLvaluer[2]) { OVDCOND = 0x18; PDC2H = dch; PDC2L = dcl; PDC1H = dch; PDC1L = dcl; }
  else if(HALL == HALLvaluer[3]) { OVDCOND = 0x09; PDC1H = dch; PDC1L = dcl; PDC0H = dch; PDC0L = dcl; }
  else if(HALL == HALLvaluer[4]) { OVDCOND = 0x21; PDC2H = dch; PDC2L = dcl; PDC0H = dch; PDC0L = dcl; }
  else if(HALL == HALLvaluer[5]) { OVDCOND = 0x24; PDC2H = dch; PDC2L = dcl; PDC1H = dch; PDC1L = dcl; }

In the above CW and CCW routines I send different sequences to the phases of the BLDC motor. Yet the motor spins in the exact same direction...I used a virtual oscilloscope on it's 3 phases and I see same sequence of voltages for both CW and CCW code routines...but how is that possible the motor to see exactly same sequence on it's phases if I'm sending different commands? Please help me identify this issue if possible(yes I know I have a different thread on this but I have made some modifications in the code and I need this kinda urgent so any help would be appreciated. Thank you!)

This is how the schematic looks like: I made an inverter with 2 L293D drivers.

2jb5iq1.jpg
 
As I have said before.... To reverse a three phase motor only two phases need to be swapped....

A B C
0 + - = 0x09
- + 0 = 0x18
- 0 + = 0x12
0 - + = 0x06
+ - 0 = 0x24
+ 0 - = 0x21

To reverse B and C are swapped

A B C
0 - + = 0x06
- 0 + = 0x12
- + 0 = 0x18
0 + - = 0x09
+ 0 - = 0x21
+ - 0 = 0x24

So the table you are using is correct!!! If I swap the two phases on the motor... It reverses!!

BTW... you keep forgetting to swap RB4 and RB5!!!

This must be an encoder problem.... I would be tempted to check the sequence for forward and reverse..

Run the simulation and place a break point on the interrupt... Write down the sequence.... Then keep rotating the reverse sequence until something happens.... I think it's slightly out..
 
Yes I was thinking that it's a problem from Proteus as well.

If I swap the two phases on the motor... It reverses!!
Do you mean if you swap the phases in proteus the motor reverses? Because I've tried that as well and the motor still spins CW. What version of proteus are you using?

Also: I checked the sequence by doing a step by step simulation and checking the sequence just by looking at each PWM signal. The signals are sent in the right order...yet the motor spins only CW no matter the sequence. I will check with interrupts as well as you said.
 
Trouble is, I have all this laid out on my home computer... Here at work I can't get the time, so I'll check out at home and send you a vid or something..

I can use V7.9 or v8.1 of ISIS.. so both do as well as each other...
 
I have done nothing with the code.... It seems to work as expected... The simulation runs a bit slow on my laptop 83% I have to set the osc to 4Mhz to get somewhere near realtime...

If no speed is selected while the motor is coasting it jitters but I doubt it would do that for real... The reverse works fine.... Are you sure you are waiting long enough for the inertia to die down so the motor can reverse??

I've done a video, but I can't find my phone's USB -> PC cable... I'll upload it to utube when I can...
 
Yeah that would be great if you can film it spinning backwards with my schematic. I have a presentation tomorrow and it'd be great to be able to prove it that the motor can actually go CCW with that code in case they won't belive me it's a simulator problem :D
 

Attachments

  • schemabun.rar
    23.2 KB · Views: 202
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top