Simple background: this brushless motor was bought at Hobbyking for less than $20 and can put out something like 600W. Although that is pretty high, it is not to be used for wheeled vehicles, which have highly dynamic loads and high current spikes. These brushless motors are intended for R/C planes' propellers, which have very steady and predictable loads. I have it connected to an electronic speed controller (ESC), which I bought, that dishes out the current at the right times to the brushless motor based on a simple pulse-width modulated signal it receives. The ESC is necessary because brushless motors operate in a totally different way from DC motors. Brushless motors are 3-phase, and as a result have three wires that need to be connected to a power source. Where you could just apply a steady voltage to DC motor and the commutator takes care of current alternation, brushless motors require more deliberate control. This control is not the subject of this post. I use a PIC to easily create and control a PWM signal using PIC's onboard timers for the ESC to interpret. So this post is basically about programming PICs specifically, to generate a PWM signal, of any flavor or kind if you like.
The signal generated here is a standard servo signal of 50 Hz (period 20 ms) with a square wave pulse that ranges in width from 1 to 2 ms.
What the software does: The software uses PIC's Timer1 and Timer0 and interrupts to make the signal, whose length varies (of the signal that can vary from 1 to 2 ms, the 50 Hz cycle is fixed) based on an analog input from a potentiometer. The PIC is constantly polling and converting the signal from a potentiometer to a value from 0 to 255, while in the background the Timers are counting down. Timer1 has a fixed time length (of course defined by me) of 20 ms, and Timer0 has a length from 1 ms to 2 ms, determined by the ADC. Timer1 dictates when the pulse, whose length is determined by Timer0, occurs. Notice that every cycle there is at least a period of 18 ms where the signal is low. The timers counting down and the potentiometer signal polling occurs simultaneously. When the Timers countdown, interrupts stop the PIC from whatever it was doing, executes a specified procedure, and then the PIC resumes whatever it was doing. In this case, the interrupts would be used to stop and start signals.
The c code:
//Using default Internal Clock of 4 Mhz
//To use TMR1 at 50 Hz and 1:1 prescaler, set offset to 45535.
//TMR0 can vary from 7 to 132, or 2 ms to 1 ms, at 1:1 prescaler.
//Use TMR0 to control pulse width, even though TMR1 has much higher resolution, because TMR1 offset is 16 bits and may require lots of time to compute proper TMR1 offset from ADC value.
#include
__CONFIG(INTIO & WDTDIS & PWRTEN & MCLRDIS & UNPROTECT \
& UNPROTECT & BORDIS & IESODIS & FCMDIS);
unsigned int pulse = 0;
//Interrupt function
static void interrupt isr(void)
{
if(T0IF)
{
RC0 = 0;
}
if(TMR1IF)
{
TMR1IF = 0;
//Start 50 Hz cycle period.
TMR1L = 0b11011111;
TMR1H = 0b10110001;
//Turn on variable pulse.
RC0 = 1;
if(RC1 == 1) //safety switch (must be pressed).
{
TMR0 = pulse;
T0IF = 0;
}
else //off.
{
TMR0 = 132;
T0IF = 0;
}
}
}
void main(void)
{
//Setting ports.
TRISA = 0x00001001; // Set A0 (for ADC) and A3 (MCLR) to input, others output
PORTA = 0x00;
TRISC = 0b00000010; //Set C1 to input for safety on switch.
PORTC = 0x00;
//ADC configuration.
ADCON1 = 0x00;//So that ADC conversion clock is set to Fosc/2.
ADCON0 = 0b00000001;//ADC enabled.
ANSEL = 0x01; // Set A0 to analog, others digital
//Timer configuration
OPTION = 0b00000010; // Timer0 configuration, 1:8 prescaler.
TMR1L = 0b11011111;
TMR1H = 0b10110001;
T1CON = 0b00000001; // Timer1 configuration, including 1:1 Prescaler and TMR1ON = 1.
//Timer interrupt enabling.
T0IE = 1;
TMR1IE = 1; // Timer1 interrupt enable, needed with PEIE and GIE bits set.
PEIE = 1; // Peripheral interrupt enable, for Timer1.
//General interrupt enabling.
GIE = 1; // Global interrupt enable, for Timer1 and Timer0.
while(1)
{
GODONE=1; // initiate conversion.
while(GODONE) continue; // Wait for conversion to finish.
pulse = 7+ADRESH*125/255;
}
}
The c code is turned into a hex file via MPLAB and I program the microcontroller with the PICKit 2. The microcontroller is a PIC16F690. Analog-to-digital conversion signal (from potentiometer) input is at A0 and ouput PWM signal is at C0. There is an input at C1 for a momentary pushbutton, which needs to be held in order for an input at C1 to be high. This is for safety, as I want it to be easy to turn the motor off by just letting go of the pushbutton. So no matter how high a speed the potentiometer is set to, nothing will happen unless the pushbutton is held.
Since the ADC gives values from 0 to 255, the resolution, or how many speed levels, you have is limited to 256. So it does not matter whether you use Timer0 or Timer1 for determining the signal length (Timer1 has a much higher temporal resolution). I use Timer0 because it probably takes less time for the PIC to do the arithmetic of converting the ADC value to the appropriate number. Timer0 uses 8 bits to define counter number (up to 255 in decimal), while Timer1 uses 16 bits (up to 65535 in decimal).
Remember, when using PICs as standalone portable devices, two things should be done: there should be a capacitor across the power supply pins (here, .1 microFarad, and yes this is absolutely necessary, else the PIC just keeps turning off and on) and a resistor tying MCLR pin to the power supply (here 10 kOhm). Also, I tied the input C1 pin to ground, so that electrical noise wont make it go high and low unintentionally.
hi, can you give me that connections of this circuit diagram?
ReplyDeleteHello, there are only a few connections so I detailed them right below the code. If you have any questions please comment.
DeleteWell, could you send me an email Would you taken photos of the circuit?
DeleteThis comment has been removed by the author.
DeleteThis comment has been removed by the author.
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteWell done Thk you up load this it use full to me. thk again
ReplyDeleteSure...
Deletegreat job perfect friend ...
ReplyDeleteBut I have a question, such as the PWM signal input to the esc?
You can reply to my email?
brian_lara87@hotmail.com
Waiting for a prompt response
Brian Lara
Or better how the pic is the connection to esc?
ReplyDeleteThank you my friend...
Brian Lara
The pic output (a pwm signal) goes directly into the white wire of the ESC. That is the only connection. Of course they have a common ground as well.
DeleteI want drive brushless with PIC 16F877 by c language
ReplyDeleteCan you help me please.....
My e-mail Air_force50@hotmail.com
Hi, have you looked at MPLAB?
ReplyDeletehttp://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en019469&part=SW007002
I use this along with the PicKit programmer hardware. I have a pickit 2, but I think there is now a pickit 3.
yes,I have pickit2 and I want to know about drive brushless with ESC same you
ReplyDeleteCan you help me please...
Did you try out my code? If so, did you get errors?
Deletetry already it errors
DeleteError 20 "ESC1.c" Line 2(1,2): Filename must start with " or <
Error 128 "ESC1.c" Line 6(1,2): A #DEVICE required before this line
Help me please?
Deletetry already it errors
ReplyDeleteError 20 "ESC1.c" Line 2(1,2): Filename must start with " or <
Error 128 "ESC1.c" Line 6(1,2): A #DEVICE required before this line
Have you tried Googling it?
ReplyDeleteIt would help to have the lines of code, too. Those sound like very basic errors. I did some quick searches of the errors, and the first results look promising.
try already it errors
ReplyDeleteError [192] C:\Microchip Solutions v2010-10-19\Project_NECTEC\Test_16F877\ESC2.c; 44.1 undefined identifier "ANSEL"
Error [192] C:\Microchip Solutions v2010-10-19\Project_NECTEC\Test_16F877\ESC2.c; 47.1 undefined identifier "OPTION"
Error [192] C:\Microchip Solutions v2010-10-19\Project_NECTEC\Test_16F877\ESC2.c; 62.1 undefined identifier "GODONE"
hey i have the same problem, can you tell me what is the answer please, my email is bgzt_11@hotmail.com
Deletehi, great work. Is it possible that u upload schematic of the circuit been used? Or email it to my mail, asperodz@rocketmail.com. Thx.
ReplyDeletehi guys, can you give me that connections of this circuit diagram please..
ReplyDeletethanks
u can send to my email ixxitdomi@gmail.com
Awesome work! And thanks sharing. I was cruising for exactly this topic, so this was very helpful. I know zilch when it comes to RC components, but just finished a pretty intensive PIC-based MCU course. Naturally, all I want to do now is build a quadcopter (and I'm the first one, right?). But I don't know how to interface the PIC with whatever signals are used in RC motor/servo-control.
ReplyDeletePWMs seem to describe control very well. In general when it comes to RC components, are they fairly easy to control/interface with the PIC, as long as you define your PWM frequency ranges right? Are there pitfalls? Good resources for the RC components newbie? Thanks much for any response!
I think using the PIC is a good way to build your own controller. There aren't any pitfalls that I am aware of. I just Google whatever it is I need, and I do not have any sites in particular to recommend.
DeleteThanks for reading, and good luck with your project!
Hi.. Im new to building quadcopters. We are building a quadcopter for our college project.
ReplyDeleteWe are trying to control the four motors using PIC18f6520.
My ESC:
http://www.rcbazaar.com/products/806-avionic-20amp.aspx
My motor:
http://www.rcbazaar.com/products/1999-avionic-c2836-kv1120-brushless-motor.aspx
I've connected the motor and battery with the ESC.
The thing is I dont know what to do with the 3 cables coming out of the ESC. I know one of them is the PWM input to the ESC.
I also generated a PWM wave and sent it to the ESC via the white cable. The motor keeps on beeping and it doesnt run.
I dont know what to do with the rest two wires. Please help me. Can you give me a circuit diagram of some sort ? Because it can help me a lot Thank you.
hi i am also same project.. 1st question why u choose the 18f6520???
Deletehi i am also same project.. 1st question why u choose the 18f6520???
DeleteDhilip, you should be able to find that out very easily.
DeleteMy particular ESC had a battery-eliminator circuit (BEC), which takes power from the same battery as the motor and regulates it to so that it can safely power the micro-controller. This way you do not need separate batteries for the micro-controller.
The two other wires are the positive and negative supply voltages provided by the BEC. Connect these wires to the Vcc and ground of your micro-controller. Of course make sure the voltages are right for your micro-controller (it probably will be).
Hi
ReplyDeleteim using this motor i want to program wit pic but your code is not work so i dont kwnow if you could help me with the diagram and the code, im using pic 16f877a mis ESC is 30A please help me, i add that im usin mplab x ide mi email is bgzt_11@hotmail.com , i hope hear you as soon as possible
thanks
You used MPLAB XC8 ?
Deletethis is my error
DeleteCONFIG(INTIO & WDTDIS & PWRTEN & MCLREN & UNPROTECT & UNPROTECT & BORDIS & IESODIS & FCMDIS);
hello sir i used this code to pic 16f877a but is have not the comment of ANSEL = 0x01; // Set A0 to analog, others digital and i want circuit of pic connection please reply me or mail me @ dkdinesheee715@gmail.com
ReplyDeleteI had the same error ANSEL and GO_DONE..I google it and find out that it was spelling mistakes..try this
Delete//Using default Internal Clock of 4 Mhz
//To use TMR1 at 50 Hz and 1:1 prescaler, set offset to 45535.
//TMR0 can vary from 7 to 132, or 2 ms to 1 ms, at 1:1 prescaler.
//Use TMR0 to control pulse width, even though TMR1 has much higher resolution, because TMR1 offset is 16 bits and may require lots of time to compute proper TMR1 offset from ADC value.
#include
__CONFIG(INTIO & WDTDIS & PWRTEN & MCLRDIS & UNPROTECT \
& UNPROTECT & BORDIS & IESODIS & FCMDIS);
unsigned int pulse = 0;
//Interrupt function
static void interrupt isr(void)
{
if(T0IF)
{
RC0 = 0;
}
if(TMR1IF)
{
TMR1IF = 0;
//Start 50 Hz cycle period.
TMR1L = 0b11011111;
TMR1H = 0b10110001;
//Turn on variable pulse.
RC0 = 1;
if(RC1 == 1) //safety switch (must be pressed).
{
TMR0 = pulse;
T0IF = 0;
}
else //off.
{
TMR0 = 132;
T0IF = 0;
}
}
}
void main(void)
{
//Setting ports.
TRISA = 0x00001001; // Set A0 (for ADC) and A3 (MCLR) to input, others output
PORTA = 0x00;
TRISC = 0b00000010; //Set C1 to input for safety on switch.
PORTC = 0x00;
//ADC configuration.
ADCON1 = 0x00;//So that ADC conversion clock is set to Fosc/2.
ADCON0 = 0b00000001;//ADC enabled.
ANSEL = 0x01; // Set A0 to analog, others digital
//Timer configuration
OPTION_REG = 0b00000010; // Timer0 configuration, 1:8 prescaler.
TMR1L = 0b11011111;
TMR1H = 0b10110001;
T1CON = 0b00000001; // Timer1 configuration, including 1:1 Prescaler and TMR1ON = 1.
//Timer interrupt enabling.
T0IE = 1;
TMR1IE = 1; // Timer1 interrupt enable, needed with PEIE and GIE bits set.
PEIE = 1; // Peripheral interrupt enable, for Timer1.
//General interrupt enabling.
GIE = 1; // Global interrupt enable, for Timer1 and Timer0.
while(1)
{
GO_DONE =1; // initiate conversion.
while(GO_DONE ) continue; // Wait for conversion to finish.
pulse = 7+ADRESH*125/255;
}
}
Dear Lordvon,
ReplyDeleteI wonder if you initialize/calibrate the esc with max and min..Because at forums with arduino they firstly calibrate esc and then esc goes to programm mode and then they programm it..Also, i use pic16f877a..Should i do any changes to your code if i want to do the same(sent a pwm to BLCD via esc)??Thank you in advance!!!
my e-mail is: sosat1991@gmail.com