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.

Inverter for controlling BLDC with PIC18f2431

Status
Not open for further replies.

Cantafford

Member
Hello,

I'm trying to control a BLDC with a PIC18F2431. I simulated the application and I created an inverter using 2 L293D drivers. Like this:
seyc5s.png

The motor is supposed to start running after I select a direction from buttons on RB6, RB7 then by pressing the start button. It's speed is also dependend on the position of that potentiometer connected to ADC0. It works just fine like this.

However that would not be usefull if I had a BLDC with high current rating since the L293D can handle only around 7 amps.
So I wanted to make an inverter of MOSFETS instead. I have created this arrangments in proteus using 2N6660 mosfets. Like this:
e9aq93.png


However when I simulate this the motor acts very weird: the motor starts running with a very low speed as long as the START button is kept pressed. If the button is released the motor decelerates to 0. The program worked fine with the inverter created with 2 L293D's so i suppose the code is good and I made some error in making that arangment of mosfets. Please help me identify the issue so the application will simulate fine. Thank you.

Here is the 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 HALLvaluer[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;

 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 == 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; }
}

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
   }
}
 
Your problem is with the top mosfets (Q1 - Q3). To turn these on the gate must be at least 2V higher than the Drain. As the drain is at 12V the gates need to be at 14V.

Mike.
 
In protues you can use a PNP to switch in 24v to turn the the top fet fully on... just include a 24v rail and then the high side will work.. Just for simulation though ( as pommie pointed out ) 14v will turn it on enough to simulate...

At least you can test you code..... I would suggest though... You are tinkering around a lot with BLDC motors For your own sanity .. Just buy a BLDC motor driver... As for simulation... The hardware can be sorted out later..
 
In protues you can use a PNP to switch in 24v to turn the the top fet fully on... just include a 24v rail and then the high side will work.. Just for simulation though ( as pommie pointed out ) 14v will turn it on enough to simulate...

At least you can test you code..... I would suggest though... You are tinkering around a lot with BLDC motors For your own sanity .. Just buy a BLDC motor driver... As for simulation... The hardware can be sorted out later..
I will buy one. I have one actually but it has it's own controller inside since it's made for an RC car. Right now however I have a project at the university to design an inverter and get the motor to run.

I was thinking of using mosfets like this along with drivers like this. Do you think it's suited for my application? These are the motor's specifications(last one on the list - 21.5T):
k1yixk.jpg


Edit: The mosfet has 130W power dissipation specified in the datasheet while my motor has 150 as seen from that table. Will that cause problems if I supply 12V on the inverter rail?
 
I've watched you for ages.... First pic then AVR now pic... It seems you are not getting the results you want to see..

When I did a motor ( Brushed ) with total PWM control... I used a Pololu 24v / 12a driver... All I needed to do was have a linear feedback and a PWM out and a direction out..

Using the Pololu I was achieving virtual ground and virtual 24v across the motor.... I was running a 4a motor at max speed and I could stall the motor and the mosfet's didn't even get hot... I could NEVER design one that good..

Why are you so stuck with a brushless system... The mosfets on my system are these https://uk.rs-online.com/web/p/mosfet-transistors/0495887/

3 milli ohm RDSon.... How much heat are these NOT taking!!
 
I've watched you for ages.... First pic then AVR now pic... It seems you are not getting the results you want to see..

When I did a motor ( Brushed ) with total PWM control... I used a Pololu 24v / 12a driver... All I needed to do was have a linear feedback and a PWM out and a direction out..

Using the Pololu I was achieving virtual ground and virtual 24v across the motor.... I was running a 4a motor at max speed and I could stall the motor and the mosfet's didn't even get hot... I could NEVER design one that good..

Why are you so stuck with a brushless system... The mosfets on my system are these https://uk.rs-online.com/web/p/mosfet-transistors/0495887/

3 milli ohm RDSon.... How much heat are these NOT taking!!
I understand your point you are right I would also rather buy one then design one but I have a project at uni to design a BLDC inverter using mosfets.
The code is just some code I had and wanted to test the inverter to see if it would work.
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top