The last motor to control for me was a DC motor.
DC stands for direct current which (unlike AC or alternating current) flows in one direction from positive to negative (this comes from conventional current theory).
This diagram displays how an AC motor works
How a DC motor works
With this understanding we can control the direction (anti/clock wise) through which the motor rotates by controlling the currents direction.
We supply the motor from the microchip through the power chip. We take two output pins (digital- on or off or PWM – speed control) and feed them into the H bridge and depending which one you turn on it dictates the directional rotation of the motor.
The speed control aspect is controlling how much current we apply to the motor as we know current is proportional to magnetic flux and also torque.
I initially tested out the motor using a simple on, off, forward and reverse control. I then decided that I wished to use PWM as it required a little more work and will be very useful to me later on with other projects.
The wiring for the Microchip is the same as my other projects ( for the power,control wires from the programmer and switch). The power chip is also the same as that in the stepper motor, but only 2 pins are being fed in and fed out from. (the feed in to the power chip is PWM1H and RD0)
Heres the first PWM code I tested
// // dsPIC30F4011 Variable Speed Control of A DC motor // Written by Aisling Lee, Last updated 11-12-2015 // #include <xc.h> #include <libpic30.h> #include <stdio.h> // Configuration settings _FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, i.e. 30 MIPS _FWDT(WDT_OFF); // Watchdog timer off _FBORPOR(MCLR_DIS); // Disable reset pin int main(void) { // Setup UART for Machine monitoring U1BRG = 48; // 38400 baud @ 30 MIPS U1MODEbits.UARTEN = 1; // Enable UART // Make RD0 and RD1 digital outputs TRISD = 0b1100; // Configure PWM // PWM period = PTPER * prescale * Tcy = 9470 * 64 * 33.33ns = 20ms _PMOD1 = 0; // PWM channel 1 mode: 0 for complementary, 1 for independent _PEN1H = 1; // PWM1H pin enable: 1 to enable, 0 to disable _PTCKPS = 3; // PWM prescaler setting: 0=1:1, 1=1:4, 2=1:16, 3=1:64 PTPER = 9470; // Set PWM time base period to 20ms (15-bit value) PDC1 = 0; // 0% duty cycle on channel 1 (16-bit value) _PTEN = 1; // Enable PWM time base to start generating pulses while(1) { if(_RC15 == 1) { // Forward fast PDC1 = 0.75 * 2 * PTPER; // 75% duty cycle LATD = 0b01; // forwards } else { // Forward slow PDC1 = 0.25 * 2 * PTPER; // 25% duty cycle LATD = 0b01; // forwards } } }
After I got that working I decided to try different speeds (duty cycle percentages ) and give it an application.
I designed a state machine for a variable speed fan. It cycles through OFF, LOW, MEDIUM and HIGH.
// // dsPIC30F4011 Variable Speed Control of A DC motor // Written by Aisling Lee, Last updated 11-01-2016 // #include <xc.h> #include <libpic30.h> #include <stdio.h> // Defining state numbers #define OFF 0 #define LOW 1 #define MEDIUM 2 #define HIGH 3 // Configuration settings _FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, i.e. 30 MIPS _FWDT(WDT_OFF); // Watchdog timer off _FBORPOR(MCLR_DIS); // Disable reset pin int main(void) { // Setup UART for Machine monitoring U1BRG = 48; // 38400 baud @ 30 MIPS U1MODEbits.UARTEN = 1; // Enable UART // Make RD0 and RD1 digital outputs TRISD = 0b1100; // Configure PWM // PWM period = PTPER * prescale * Tcy = 9470 * 64 * 33.33ns = 20ms _PMOD1 = 0; // PWM channel 1 mode: 0 for complementary, 1 for independent _PEN1H = 1; // PWM1H pin enable: 1 to enable, 0 to disable _PTCKPS = 3; // PWM prescaler setting: 0=1:1, 1=1:4, 2=1:16, 3=1:64 PTPER = 9470; // Set PWM time base period to 20ms (15-bit value) PDC1 = 0; // 0% duty cycle on channel 1 (16-bit value) _PTEN = 1; // Enable PWM time base to start generating pulses //my variables int ms=30000; int cycle=20*ms; double second =50*cycle; double pause = second; int state ; _TRISC15 = 1; state = OFF; while(1) { if(state == OFF) // Motor Off { LATD = 0b00; // off if(_RD3 == 1) while(_RD3 == 1); __delay32(pause); state = LOW; printf("OFF\n"); //monitoring } if(state == LOW) // Motor slow { // Forward slow PDC1 = 0.25 * 2 * PTPER; // 25% duty cycle LATD = 0b01; // forwards if(_RD3 == 1) while(_RD3 == 1); __delay32(pause); state = MEDIUM; printf("LOW\n"); //monitoring } if(state == MEDIUM) // Motor medium { // Forward slow PDC1 = 0.5 * 2 * PTPER; // 50% duty cycle LATD = 0b01; // forwards if(_RD3 == 1) __delay32(pause); state = HIGH; printf("MEDIUM\n"); //monitoring } if(state == HIGH) // Motor fast { // Forward slow PDC1 = 0.75 * 2 * PTPER; // 75% duty cycle LATD = 0b01; // forwards if(_RD3 == 1) while(_RD3 == 1); __delay32(pause); state = OFF; printf("HIGH\n"); //monitoring } }}
There was a few issues with coding this as the time allowed to press the switch and for it to go to the next state was tricky this you’ll see I’ve implemented loops and delays to try allow enough time for the user to activate the switch. Even then still I found at times the chip operated too fast and I utilized  the UART tool to communicate and let me know as to what state I was in (or getting stuck as it got to a point where I was unable to turn it off) this pointed to as I had previously mentioned the physical speed of the switch not matching that of the code and causes intermittent errors.
Demonstration of a Variable Speed Fan,
As you can see it does not cycle perfectly through the 4 states and at times it is difficult to differentiate between the speeds, that is why I added the LED as it feeds from the PWM1H pin that controls the motor.I spent a long time trying to reduce and eradicate the errors but depending on your speed and how long you hold the switch it does impact the cycles still. I plan to continue looking into this in my own time outside of this project.
After it being pointed out to me that within the if statements (for the switch on RD3) within each of the various states, it was my syntax that was the source of my issue (code cycling through the commands and executing them in an undesired fashion). I altered the code so as it now looks like this,
// // dsPIC30F4011 Variable Speed Control of A DC motor // Written by Aisling Lee, Last updated 14-01-2016 // #include <xc.h> #include <libpic30.h> #include <stdio.h> // Defining state numbers #define OFF 0 #define LOW 1 #define MEDIUM 2 #define HIGH 3 // Configuration settings _FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, i.e. 30 MIPS _FWDT(WDT_OFF); // Watchdog timer off _FBORPOR(MCLR_DIS); // Disable reset pin int main(void) { // Setup UART for Machine monitoring U1BRG = 48; // 38400 baud @ 30 MIPS U1MODEbits.UARTEN = 1; // Enable UART // Make RD0 and RD1 digital outputs TRISD = 0b1100; // Configure PWM // PWM period = PTPER * prescale * Tcy = 9470 * 64 * 33.33ns = 20ms _PMOD1 = 0; // PWM channel 1 mode: 0 for complementary, 1 for independent _PEN1H = 1; // PWM1H pin enable: 1 to enable, 0 to disable _PTCKPS = 3; // PWM prescaler setting: 0=1:1, 1=1:4, 2=1:16, 3=1:64 PTPER = 9470; // Set PWM time base period to 20ms (15-bit value) PDC1 = 0; // 0% duty cycle on channel 1 (16-bit value) _PTEN = 1; // Enable PWM time base to start generating pulses //my variables int ms=30000; int cycle=20*ms; double second =50*cycle; double pause = second; int state ; _TRISC15 = 1; state = OFF; LATD = 0b00; printf("START\n"); //monitoring while(1) { if(state == OFF) // Motor Off { LATD = 0b00; // off if(_RD3 == 1) { while(_RD3 == 1); __delay32(pause); state = LOW; } printf("OFF\n"); //monitoring } if(state == LOW) // Motor Off { // Forward slow PDC1 = 0.25 * 2 * PTPER; // 25% duty cycle LATD = 0b01; // forwards if(_RD3 == 1) { while(_RD3 == 1); __delay32(pause); state = MEDIUM; } printf("LOW\n"); //monitoring } if(state == MEDIUM) // Motor Off { // Forward slow PDC1 = 0.5 * 2 * PTPER; // 50% duty cycle LATD = 0b01; // forwards if(_RD3 == 1) { while(_RD3 == 1); __delay32(pause); state = HIGH; } printf("MEDIUM\n"); //monitoring } if(state == HIGH) // Motor Off { // Forward slow PDC1 = 0.75 * 2 * PTPER; // 75% duty cycle LATD = 0b01; // forwards if(_RD3 == 1) { while(_RD3 == 1); __delay32(pause); state = OFF; } printf("HIGH\n"); //monitoring } } }
Here is footage of the new code performing as desired,
Hi Aisling,
I think the problem with the state changes are to do with missing curly brackets in the if statement where you check _RD3 (the switch input). I think you need something like this:
if(state == OFF) // Motor Off
{
LATD = 0b00; // off
if (_RD3 == 1)
{
while(_RD3 == 1);
__delay32(pause);
state = LOW;
}
printf(“OFF\n”); //monitoring
}
Without those middle set of curly brackets, “__delay32(pause);” and “state = LOW;” are not conditional on the if statement – they’re just executed every time.
Ted
LikeLike
Thanks Ted im going to try execute that right now. Ill post an update for it as well
LikeLike
There’s no rush at all. It won’t make a significant difference to the grade, but it would just be nice to have it fixed for any readers who find their way here in the future. Your blog is excellent overall.
Ted
LikeLiked by 1 person
Just tried it out there and it worked, I’ve updated the blog (just continued on from the last paragraph) with the footage and the new code thanks Ted 🙂
LikeLike
Brilliant – that was quick work!
Thanks,
Ted
LikeLike
Well it just so happened I had all my electronics kit out on the desk as I was working on my 3D printer last night (which ill be putting up on the blog). Essentially I just had to log in and change my code everything else I’ve shortcuts to on my desktop. This semester has made my work rate very efficient.
Thanks again Ted.
LikeLike
I look forward to seeing the 3D printer. That should come in handy for your final-year project!
LikeLike
Pingback: Last updated 20/04/2016 | Aisling Lee