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.

BLDC sensored control using PIC18f2431

Status
Not open for further replies.

Cantafford

Member
Hello,

I'm trying to control a bldc motor using PIC18f2431. For starters I just want to get it to spin. I want to simulate it in proteus and this is the schematic:
qqze2q.png


I want to use input capture modules cap1, cap2 and cap3 to detect the current status of the hall sensors and depending on what those values are send a specific sequence to the phases of the motor. CAP1, 2 and 3 are on RA2, RA3 and RA4.

Here is the truth table for the phase sequence:
jjr96f.png


In my code I want to use INPUT CAPTURE interrupt on every falling edge(of all cap's) to detect when the sensor changed state. When that happens generate an interrupt and read the whole capture inputs(1,2,3) pins to see what the current state of the hall sensors is and generate the phase sequence.

This is the code I wrote:

The main file:

Code:
/*
* File:   main.c
* Author: Paul
*
* Created on March 23, 2016, 5:27 PM
*/

#include <stdio.h>
#include <stdlib.h>
#include "header.h"

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

// Capture Interrupt Service Routine

void interrupt CheckHallValue()
{
  IC1IF = 0; IC2QEIF = 0; IC3DRIF = 0;
  HALL = PORTA >> 2 & 0b00000111; // read the capture pins to get hall sensor state
  if(HALL == HALLvalue[0]) LATB = 0b11100100;      // and give
  else if(HALL == HALLvalue[1]) LATB = 0b11000110; // appropiate phase sequence
  else if(HALL == HALLvalue[2]) LATB = 0b11010010;
  else if(HALL == HALLvalue[3]) LATB = 0b11011000;
  else if(HALL == HALLvalue[4]) LATB = 0b11001001;
  else if(HALL == HALLvalue[5]) LATB = 0b11100001;
}

void main()
{
OSCCON = 0x7F; // frequency is 8Mhz
TRISA = 0b11111111; // PORTA is input(CAP's + POT)
GIE = 1; // enable global interrupts

// 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
IC1IF = 0; // clear IC1 interrupt status flag
IC1IE = 1; // enable IC1 interrupt

IC2QEIF = 0; // clear IC2 interrupt status flag
IC2QEIE = 1; // enable IC2 interrupt

IC3DRIF = 0; // clear IC3 interrupt status flag
IC3DRIE = 1; // enable IC3 interrupt


T5SYNC = 0;
T5CON = 0b01011001;

}

And the header.h
Code:
/*
* File:   header.h
* Author: Paul
*
* Created on March 23, 2016, 5:26 PM
*/


// PIC18F2431 Configuration Bit Settings

// 'C' source line config statements

#include <xc.h>

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

// CONFIG1H
#pragma config OSC = IRCIO      // Oscillator Selection bits (Internal oscillator block, port function on RA6 and port function on RA7)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = ON        // Internal External Oscillator Switchover bit (Internal External Switchover mode enabled)

// CONFIG2L
#pragma config PWRTEN = OFF     // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bits (Brown-out Reset disabled)
// BORV = No Setting

// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
#pragma config WDPS = 32768     // Watchdog Timer Postscale Select bits (1:32768)
#pragma config WINEN = OFF      // Watchdog Timer Window Enable bit (WDT window disabled)

// CONFIG3L
#pragma config PWMPIN = OFF     // PWM output pins Reset state control (PWM outputs disabled upon Reset (default))
#pragma config LPOL = HIGH      // Low-Side Transistors Polarity (PWM0, 2, 4 and 6 are active-high)
#pragma config HPOL = HIGH      // High-Side Transistors Polarity (PWM1, 3, 5 and 7 are active-high)
#pragma config T1OSCMX = ON     // Timer1 Oscillator MUX (Low-power Timer1 operation when microcontroller is in Sleep mode)

// CONFIG3H
#pragma config MCLRE = OFF      // MCLR Pin Enable bit (Disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = ON         // Low-Voltage ICSP Enable bit (Low-voltage ICSP enabled)

// CONFIG5L
#pragma config CP0 = OFF        // Code Protection bit (Block 0 (000200-000FFFh) not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 (001000-001FFF) not code-protected)
#pragma config CP2 = OFF        // Code Protection bit (Block 2 (002000-002FFFh) not code-protected)
#pragma config CP3 = OFF        // Code Protection bit (Block 3 (003000-003FFFh) not code-protected)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot Block (000000-0001FFh) not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 (000200-000FFFh) not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 (001000-001FFF) not write-protected)
#pragma config WRT2 = OFF       // Write Protection bit (Block 2 (002000-002FFFh) not write-protected)
#pragma config WRT3 = OFF       // Write Protection bit (Block 3 (003000-003FFFh) not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot Block (000000-0001FFh) not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 (000200-000FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 (001000-001FFF) not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF      // Table Read Protection bit (Block 2 (002000-002FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF      // Table Read Protection bit (Block 3 (003000-003FFFh) not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot Block (000000-0001FFh) not protected from table reads executed in other blocks)


#define _XTAL_FREQ 8000000

When I compile this code the motor does not start at all in proteus. Hall sensors stay in: hall1-low, hall2-low, hall3-high and nothing changes.

Please help me correct this. Thank you for reading!
 
Last edited:
Q1~3 need to be pnp's the emitter is at 12v and the base is at 5v...

ALSO!! Read your messages.... There are 7195... I would assume the pic18 device is in reset!!

NOTE TO ALL POSTING.... Isis doesn't need resistors while simulating!!
 
Hello, thank you for your answer.

Q1~3 need to be pnp's the emitter is at 12v and the base is at 5v...

I'm not sure I understand what you mean about the transistors. Do you mean I have to replace the Q1, Q2 and Q3 with PNP's and let Q4, Q5 and Q6 be NPN's? I have never seen such an inverter topology. Also why do you say I should keep their emitters at 12V and base at 5V? What I want to do is control the transistors with PWM signals comming from the PIC(I will try to impose the speed later on). So therefore I connected the PWM's comming from the PIC to the transistors bases.

ALSO!! Read your messages.... There are 7195... I would assume the pic18 device is in reset!!
MCLR pin is disabled if that's what you mean.

NOTE TO ALL POSTING.... Isis doesn't need resistors while simulating!!
Yes, you are right. But I may end up doing the PCP design as well that's why they are there.
 
Q1 Q2 and Q3 are connected high... If you connect the base of these to a pic pin, the pin will only provide 5v

As the voltage at the motor will be higher than 5v, the three NPN's won't conduct..

The messages are there for some reason??? What are they telling you ( yellow means trouble )

The POSTING comment was for others...
 
Ok I have followed your instructions and got the motor to move but it bounces back and forth instead of spinning in a certain direction.
This is the schematic:
2mgjn78.png


Q1,3,5 are NPN's so they will be turned on by a low signal while Q0,2,4 are PNP's so they are supposed to turn on when they have current in base.
Again, the phase sequence is supposed to be this:
jjr96f.png


This is the code:
Code:
#include <stdio.h>
#include <stdlib.h>
#include "header.h"

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

// Capture Interrupt Service Routine

void interrupt CheckHallValue()
{
  IC1IF = 0; IC2QEIF = 0; IC3DRIF = 0;
  HALL = PORTA >> 2 & 0b00000111; // read the capture pins to get hall sensor state
  if(HALL == HALLvalue[0]) LATB = 0b11001110;      // and give
  else if(HALL == HALLvalue[1]) LATB = 0b11101100; // appropiate phase sequence
  else if(HALL == HALLvalue[2]) LATB = 0b11111000;
  else if(HALL == HALLvalue[3]) LATB = 0b11110010;
  else if(HALL == HALLvalue[4]) LATB = 0b11100011;
  else if(HALL == HALLvalue[5]) LATB = 0b11001011;
}

void main()
{
OSCCON = 0b01001111; // frequency is 1Mhz
TRISA = 0b11111111; // PORTA is input(CAP's + POT)
TRISB = 0b11000000;
GIE = 1; // enable global interrupts

// 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
IC1IF = 0; // clear IC1 interrupt status flag
IC1IE = 1; // enable IC1 interrupt

IC2QEIF = 0; // clear IC2 interrupt status flag
IC2QEIE = 1; // enable IC2 interrupt

IC3DRIF = 0; // clear IC3 interrupt status flag
IC3DRIE = 1; // enable IC3 interrupt


T5SYNC = 0;
T5CON = 0b01011001;
TMR5CS = 0;

Now if I run that code in simulation the transistors of the inverter bridge will get in this state and won't change at all:
15xke14.png

Is like the interrupt routine will never take place and the motor will just move back and forth.


I tried running this code to see if the motor spins normally thinking that maybe I have done something wrong with the interrupt routine:
Code:
void main()
{
OSCCON = 0b01001111; // frequency is 1MHz
TRISB = 0b11000000; // PORTB is output

if(PORTAbits.RA2==1 && PORTAbits.RA3==0 && PORTAbits.RA4==1) LATB = 0b11001110;      // and give
else if(PORTAbits.RA2==1 && PORTAbits.RA3==0 && PORTAbits.RA4==1) LATB = 0b11101100; // appropiate phase sequence
else if(PORTAbits.RA2==1 && PORTAbits.RA3==0 && PORTAbits.RA4==1) LATB = 0b11111000;
else if(PORTAbits.RA2==1 && PORTAbits.RA3==0 && PORTAbits.RA4==1) LATB = 0b11110010;
else if(PORTAbits.RA2==1 && PORTAbits.RA3==0 && PORTAbits.RA4==1) LATB = 0b11100011;
else if(PORTAbits.RA2==1 && PORTAbits.RA3==0 && PORTAbits.RA4==1) LATB = 0b11001011;

Still same thing. The transistors get stuck in the state shown in the picture above. Motor spins little CW, little CCW.

I have also tried sending the phase sequence to the motor without reading the state of the hall sensors like this to see if the transistors change state at all:
Code:
for(int delay=0; delay<5; delay++) __delay_ms(5);
LATB = 0b11001110;      // and give
for(int delay=0; delay<5; delay++) __delay_ms(5);
LATB = 0b11101100; // appropiate phase sequence
for(int delay=0; delay<5; delay++) __delay_ms(5);
LATB = 0b11111000;
for(int delay=0; delay<5; delay++) __delay_ms(5);
LATB = 0b11110010;
for(int delay=0; delay<5; delay++) __delay_ms(5);
LATB = 0b11100011;
for(int delay=0; delay<5; delay++) __delay_ms(5);
LATB = 0b11001011;
for(int delay=0; delay<5; delay++) __delay_ms(5);
In this case the transistors will change state according to the LATB value and the motor will spin back and forth just like before(altough it does run a little longer in each direction).

Yes I know I wrote a lot I have a lot of questions and I apologise if I haven't explained my issues clear enough. I will explain again if something's not clear. Thanks for reading.
 
Step 1.... I used BC182 and BC212 transistor models... Step 2... You need to earth the negatative side of the battery so the pic can operate the transistors.... Step 3... I swapped A and C on the BLDC motor...

Lastly!!!!!!!!! I realised that you haven't set the PEIE ( peripheral interrupt enable bit!!) Now it works...
 
Ok I have done what you said. I set PEIE.This is the code:
Code:
#include <stdio.h>
#include <stdlib.h>
#include "header.h"

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

// Capture Interrupt Service Routine

void interrupt CheckHallValue()
{
  IC1IF = 0; IC2QEIF = 0; IC3DRIF = 0;
  HALL = PORTA >> 2 & 0b00000111; // read the capture pins to get hall sensor state
  if(HALL == HALLvalue[0]) LATB = 0b11001110;      // and give
  else if(HALL == HALLvalue[1]) LATB = 0b11101100; // appropiate phase sequence
  else if(HALL == HALLvalue[2]) LATB = 0b11111000;
  else if(HALL == HALLvalue[3]) LATB = 0b11110010;
  else if(HALL == HALLvalue[4]) LATB = 0b11100011;
  else if(HALL == HALLvalue[5]) LATB = 0b11001011;
}

void main()
{
OSCCON = 0b01001111; // frequency is 1Mhz
TRISA = 0b11111111; // PORTA is input(CAP's + POT)
TRISB = 0b11000000;
GIE = 1; // enable global interrupts
GIEH = 1;
PEIE = 1;

// 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

//TMR5 Configuration
//T5SYNC = 0;
//T5CON = 0b01011001;
//TMR5CS = 0;
T5CON = 0b00000101;

}

And this is the schematic(I used those transistors you specified and grounded the - of the battery and swapped A and C phases:
9j17gx.png


The motor still acts the same way(going back and forth). My transistors are stuck in a state and won't change at all. I made a video:
View My Video

It's like the program never enters the interrupt routine. Maybe I'm doing something wrong with the TMR5 configuration. On the pic's datasheet on input capture section it says: "
When in Counter mode, the counter must be configured as the synchronous counter only (TMR5SYNC = 0). When configured in Asynchronous mode, the IC module will not work properly."
I have initialised the TMR5 module like this: T5CON = 0b00000101;
 
Right!!!!!! This line
HALL = (PORTA >> 2) & 0x7; ..... I had to put the brakets around the first part as it was always comming out 0..

Also.... ANSEL0 = 0; ( I forgot to check this aswell )

I also included a LATB = xxxxxxx to kick start the thing.... Then Weeeeeeeee off it went!!!

WOT I DID!!
C:
#include <stdio.h>
#include <stdlib.h>
#include "cantafford.h"

char HALL;
int HALLvalue[6] = { 0b00000101, 0b00000100, 0b00000110, 0b00000010, 0b00000011, 0b00000001 };

// Capture Interrupt Service Routine

void interrupt CheckHallValue()
{
  IC1IF = 0; IC2QEIF = 0; IC3DRIF = 0;
  HALL = (PORTA >> 2) & 0x7; // read the capture pins to get hall sensor state
  if(HALL == HALLvalue[0]) LATB = 0b11001110;  // and give
  else if(HALL == HALLvalue[1]) LATB = 0b11101100; // appropiate phase sequence
  else if(HALL == HALLvalue[2]) LATB = 0b11111000;
  else if(HALL == HALLvalue[3]) LATB = 0b11110010;
  else if(HALL == HALLvalue[4]) LATB = 0b11100011;
  else if(HALL == HALLvalue[5]) LATB = 0b11001011;
}

void main()
{
OSCCON = 0b01001100; // frequency is 1Mhz
TRISA = 0b11111111; // PORTA is input(CAP's + POT)
TRISB = 0b11000000;
ANSEL0 = 0;
GIE = PEIE = 1; // enable global interrupts

// 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
IC1IF = 0; // clear IC1 interrupt status flag
IC1IE = 1; // enable IC1 interrupt

IC2QEIF = 0; // clear IC2 interrupt status flag
IC2QEIE = 1; // enable IC2 interrupt

IC3DRIF = 0; // clear IC3 interrupt status flag
IC3DRIE = 1; // enable IC3 interrupt


T5SYNC = 0;
T5CON = 0b01011001;
TMR5CS = 0;
LATB = 0b11001011;
while(1)
   {

   }
}
 
One more little question though. I have replaced all my transistors with PNP's and changed the sequence in the code so they all can be turned on with high and off with low signals to simplify the code. I also swapped A and C and changed the phase sequence in the code.
The program works fine but when the motor starts it goes into reverse direction for 1,2 seconds then it accelerates in the proper direction(I think a hardware motor would jerk a bit at start-up).
Also the motor does not accelerate as fast as in the schematic that I posted(the one with both NPN's and PNP's).
Any ideea why and how can I fix this?
 
Last edited:
Yep! I used the wrong initial kick start... Use the first one not the last one.... I sused that out as well!!!
Right. I have used the kickstart and now it starts fine doesn't go in the other direction :D. Still it accelerates slower than when I use PNP's on top of my inverter bridge. Any ideea why?

Also when I'm using PNPs on top I don't even need the kickstart.

Also a question about starting of a BLDC motor: Is it ok to start it with a kickstart? Shouldn't it just read the state of the hall sensors and figure out the phase sequence on it's own?
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top