0

Im using the PIC 18 microcontroller to control the speed of a DC Motor using PWM. I have managed to get it to spin using the code below. And I have tested that my H-Bridge is 100% functional.

However, when I switch on my circuit, 12V to the Motor and 5V to the logic, And I send a command to the circuit using my RS232 communication module, (which I have tested and it recieves and transmits correctly), the program resets and the current on the bench power supply falls to 0A. Sometimes the motor jerks slighty, almost as if its trying to spin, but then stops.

Any ideas where I could be going wrong?

/* 
 * File:   serial.c
 * Author: Chris Lombaard
 *
 * Created on September 13, 2013, 2:39 PM
 */

#pragma config FOSC = INTIO7    // Oscillator Selection bits (Internal oscillator block, CLKOUT function on OSC2)
#pragma config PLLCFG = OFF     // 4X PLL Enable (Oscillator used directly)
#pragma config PRICLKEN = ON    // Primary clock enable bit (Primary clock is always enabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)
#pragma config PWRTEN = OFF     // Power-up Timer Enable bit (Power up timer disabled)
#pragma config BOREN = SBORDIS  // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
#pragma config BORV = 190       // Brown Out Reset Voltage bits (VBOR set to 1.90 V nominal)
#pragma config WDTEN = OFF       // Watchdog Timer Enable bits (WDT is always enabled. SWDTEN bit has no effect)
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)
#pragma config CCP2MX = PORTC1  // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = ON      // PORTB A/D Enable bit (PORTB<5:0> pins are configured as analog input channels on Reset)
#pragma config CCP3MX = PORTB5  // P3A/CCP3 Mux bit (P3A/CCP3 input/output is multiplexed with RB5)
#pragma config HFOFST = ON      // HFINTOSC Fast Start-up (HFINTOSC output and ready status are not delayed by the oscillator stable status)
#pragma config T3CMX = PORTC0   // Timer3 Clock input mux bit (T3CKI is on RC0)
#pragma config P2BMX = PORTD2   // ECCP2 B output mux bit (P2B is on RD2)
#pragma config MCLRE = EXTMCLR  // MCLR Pin Enable bit (MCLR pin enabled, RE3 input pin disabled)
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF         // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled if MCLRE is also 1)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))
#pragma config CP0 = OFF        // Code Protection Block 0 (Block 0 (000800-001FFFh) not code-protected)
#pragma config CP1 = OFF        // Code Protection Block 1 (Block 1 (002000-003FFFh) not code-protected)
#pragma config CP2 = OFF        // Code Protection Block 2 (Block 2 (004000-005FFFh) not code-protected)
#pragma config CP3 = OFF        // Code Protection Block 3 (Block 3 (006000-007FFFh) not code-protected)
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block (000000-0007FFh) not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM not code-protected)
#pragma config WRT0 = OFF       // Write Protection Block 0 (Block 0 (000800-001FFFh) not write-protected)
#pragma config WRT1 = OFF       // Write Protection Block 1 (Block 1 (002000-003FFFh) not write-protected)
#pragma config WRT2 = OFF       // Write Protection Block 2 (Block 2 (004000-005FFFh) not write-protected)
#pragma config WRT3 = OFF       // Write Protection Block 3 (Block 3 (006000-007FFFh) not write-protected)
#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-0007FFh) not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)
#pragma config EBTR0 = OFF      // Table Read Protection Block 0 (Block 0 (000800-001FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection Block 1 (Block 1 (002000-003FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF      // Table Read Protection Block 2 (Block 2 (004000-005FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF      // Table Read Protection Block 3 (Block 3 (006000-007FFFh) not protected from table reads executed in other blocks)
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot Block (000000-0007FFh) not protected from table reads executed in other blocks)

#include <P18F45K22.h>
#include <xc.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define _XTAL_FREQ 4000000
#define length(x) (sizeof(x) / sizeof(x[0]))    //Length of array

void writeUART(const unsigned char string[]);
void setup(void);
void inputCheck(void);
void stepF(void);
void stepB(void);
unsigned char buffer[8] = {'\0'};
unsigned char prevPos = 0;
unsigned char currPos = 0;
unsigned char bufferLength;
unsigned char direction = 0;
unsigned char speed = 0;
unsigned char isSetup = 0;


char main(void){
    if(isSetup == 0){
        setup();
        writeUART("ERD 320 Practical 2 ----- Group 1\n");
        writeUART("JC Lombaard - 11028786\n");
        writeUART("VFDC Henriques - 11100232\n");
        writeUART("William Reeler - 11228866\n");
        writeUART("FAN POSITION: 1");
        PORTDbits.RD1 = 1;
        PORTDbits.RD0 = 0;
        PORTCbits.RC3 = 0;
        PORTCbits.RC0 = 0;
        PORTAbits.RA6 = 0;
    }

    while(1){
        if(PORTEbits.RE1 == 1)
            stepB();
        if(PORTEbits.RE0 == 1){
            writeUART("\nFan calibrated!\n");
            break;
        }
    }

    bufferLength = 0;
    while (1);
    return (EXIT_SUCCESS);
}

void interrupt high_priority isr_high(void) {
    if(PIR1bits.RC1IF == 1){
        if(RCREG1 == '\n'){
            buffer[bufferLength++] = '\0';
            bufferLength = 0;
            inputCheck();
        }else{
            buffer[bufferLength++] = RCREG1;
            PIR1bits.RC1IF = 0;
        }
    }
}

void interrupt low_priority isr_low(void){
    PIR1bits.TMR2IF = 0;
    TMR2 = 0;
}

void inputCheck(void) {
    const unsigned char commands[11][3] = {"S0", "S1", "S2", "S3", "S4", "P1", "P2", "P3", "P4", "R", "F"};
    unsigned char choice = 0;
    for(; choice < 11; choice++)
        if (strcmp(buffer, commands[choice]) == 0){
            break;
        }
    switch(choice){        
        case 0:
            writeUART("FAN SPEED: 0% DC");
            PORTA = 0b00111111;
            speed = 0;
            if(direction == 0){
                CCPR1L = 0x00;
            }else{
                CCPR2L = 0x00;
            }

          break;
        case 1:
             writeUART("FAN SPEED: 10% DC");
             PORTA = 0b00000110;
             speed = 0b01101110 ;
            if(direction == 0){
                CCPR1L = 0b11010000 ;
                __delay_ms(100);
                CCPR1L = 0b01101110 ;
            }else{
                CCPR2L = 0b11010000 ;
                __delay_ms(100);
                CCPR2L = 0b01101110 ;
            }
          break;
        case 2:
            writeUART("FAN SPEED: 30% DC");
            PORTA = 0b01011011;
            speed = 0b10001100;
            if(direction == 0){
                CCPR1L = 0b11010000;
                __delay_ms(100);
                CCPR1L = 0b10001100;
            }else{
                CCPR2L = 0b11010000 ;
                __delay_ms(100);
                CCPR2L = 0b10001100 ;
            }
          break;
        case 3:
            writeUART("FAN SPEED: 60% DC");
            PORTA = 0b01001111;
            speed = 0b10101101;
            if(direction == 0){
                CCPR1L = 0b11010000 ;
                __delay_ms(100);
                CCPR1L = 0b10101101 ;
            }else{
                CCPR2L = 0b11010000 ;
                __delay_ms(100);
                CCPR2L = 0b10101101 ;
            }
          break;
        case 4:
            writeUART("FAN SPEED: 90% DC");
            PORTA = 0b01100110;
            speed = 0b11010000 ;
            if(direction == 0){
                CCPR1L = 0b11010000;
            }else{
                CCPR2L = 0b11010000;
            }
          break;
        case 5:
          currPos = 1;
          if(prevPos > currPos){
              for(int i = prevPos+1; i  > currPos; i--)
                stepB();
          }else{

          }
          writeUART("FAN POSITION: 1");
          PORTDbits.RD1 = 1;
          PORTDbits.RD0 = 0;
          PORTCbits.RC3 = 0;
          PORTCbits.RC0 = 0;
          prevPos = currPos;
          break;
        case 6:
          prevPos = currPos;
          currPos = 2;
          if(prevPos > currPos){
              for(int i = prevPos+1; i  > currPos; i--)
                stepB();
          }else{
              for(int i = currPos+1; i  > prevPos; i--)
                stepF();
          }
          writeUART("FAN POSITION: 2");
          PORTDbits.RD1 = 0;
          PORTDbits.RD0 = 1;
          PORTCbits.RC3 = 0;
          PORTCbits.RC0 = 0;
          prevPos = currPos;
          break;
        case 7:
          prevPos = currPos;
          currPos = 3;
          if(prevPos > currPos){
              for(int i = prevPos+1; i  > currPos; i--)
                stepB();
          }else{
              for(int i = currPos+1; i  > prevPos; i--)
                stepF();
          }
          writeUART("FAN POSITION: 3");
          PORTDbits.RD1 = 0;
          PORTDbits.RD0 = 0;
          PORTCbits.RC3 = 1;
          PORTCbits.RC0 = 0;
          prevPos = currPos;
          break;
        case 8:
          prevPos = currPos;
          currPos = 4;
          if(prevPos > currPos){
              for(int i = prevPos+1; i  > currPos; i--)
                stepB();
          }else{
              for(int i = currPos+1; i  > prevPos; i--)
                stepF();
          }
          writeUART("FAN POSITION: 4");
          PORTDbits.RD1 = 0;
          PORTDbits.RD0 = 0;
          PORTCbits.RC3 = 0;
          PORTCbits.RC0 = 1;
          prevPos = currPos;
          break; 
        case 9:
            direction = 1;
            CCP1CON = 0b00000000;
            CCP2CON = 0b00111100;
            CCPR2L = speed;
            writeUART("FAN DIRECTION: REVERSED");
          break;
        case 10:
            direction = 0;
            CCP1CON = 0b00111100;
            CCP2CON = 0b00000000;
            CCPR1L = speed;
            writeUART("FAN DIRECTION: FORWARD");
          break;
        default:
          break;
    }
}

void stepF(void){
    for(int i = 0; i < 1; i++){
        PORTB = 0b0001;
        __delay_ms(100); //Delay between transitions
        PORTB = 0b0010;
        __delay_ms(100); //Delay between transitions
        PORTB = 0b0100;
        __delay_ms(100); //Delay between transitions
        PORTB = 0b1000;
        __delay_ms(100); //Delay between transitions
    }
}

void stepB(void){
    for(int i = 0; i < 1; i++){
        PORTB = 0b1000;
        __delay_ms(100); //Delay between transitions
        PORTB = 0b0100;
        __delay_ms(100); //Delay between transitions
        PORTB = 0b0010;
        __delay_ms(100); //Delay between transitions
        PORTB = 0b0001;
        __delay_ms(100); //Delay between transitions
    }
}

void defaultPos(void){
    PORTB = 0b1000;
    __delay_ms(100); //Delay between transitions
    PORTB = 0b0100;
    __delay_ms(100); //Delay between transitions
    PORTB = 0b0010;
    __delay_ms(100); //Delay between transitions
    PORTB = 0b0001;
    __delay_ms(100); //Delay between transitions
}

void writeUART(const unsigned char string[]){
    for(unsigned char j = 0; j < strlen(string); j++){
        TXREG1 = string[j];
        __delay_us(1000);
    }
}

void setup(void){
    isSetup = 1;
    //PORTC
    PORTC = 0x00;
    LATC = 0x00;
    TRISC = 0xC0; //Set RC6 & RC7 as inputs for EUSART
    TRISCbits.RC6 = 0;
    TRISCbits.RC7 = 1;
    ANSELC = 0x00;

    //PORTD
    PORTD = 0x00;
    LATD = 0x00;
    TRISD = 0x00;
    ANSELD = 0x00;

    //PORTE
    PORTE = 0x00;
    LATE = 0x00;
    TRISEbits.RE0 = 1;
    TRISEbits.RE1 = 1;
    ANSELE = 0x00;

    //PORTB
    PORTB = 0x00;
    LATB = 0x00;
    TRISB = 0x00;
    ANSELB = 0x00;

    PORTA = 0x00;
    LATA = 0x00;
    TRISA = 0x00;
    ANSELA = 0x00;

    //Oscillator
    OSCCON = 0b01011100; //4 MHz oscillator

    //EUSART
    TXSTA1bits.BRGH = 1; //Highspeed baudrate
    BAUDCON1bits.BRG16 = 0;
    SPBRG1 = 12; //Baudrate of 19230 (FOSC = 4 MHz, BRGH = 1, BRG16 = 0)
    TXSTA1bits.SYNC = 0; //Asynchronous
    RCSTA1bits.SPEN = 1; //Enable rx & tx pins as serial pins
    RCSTA1bits.CREN = 1; //Enable continuous reception, enable receiver
    TXSTA1bits.TXEN = 1; //Enable transmitter
    TXREG1 = 0x00;
    RCREG1 = 0x00;

    //Interrupts
    RCONbits.IPEN = 1; //Enable priorities
    INTCONbits.GIE_GIEH = 1; //Enable high priority interrupts
    INTCONbits.PEIE_GIEL = 1; //Enable low priority interrupts
    PIE1bits.TMR2IE = 1;
    IPR1bits.TMR2IP = 0;
    PIE1bits.RC1IE = 1; //Enable RX interrupt
    PIR1bits.RC1IF = 0; //Clear interrupt flag
    IPR1bits.RC1IP = 1; //High priority for RX interrupts

    //PWM
    PR2 = 0b11111001 ;
    T2CON = 0b00000100; //1 KHz pulse frequency on CCP1 pin
    CCPR1L = 0x00;
    CCPR2L = 0x00;

    CCP1CON = 0b00111100;
    CCP2CON = 0b00000000;
    TMR2 = 0;
}
Chris
  • 651
  • 2
  • 10
  • 16
  • There are too many lines... Is the reset reproducible? If yes, did you identify where in the program you get the reset? – ouah Oct 02 '13 at 21:55
  • 2
    Are you sure you should call `writeUART` or `__delay_ms` from a high priority interrupt routine (or rather, inputCheck that is called by one) If you have a watchdog timer enabled (can't quite remember how that works in a PIC) it may reset while you're waiting inside the high prio ISR...? – Joachim Isaksson Oct 02 '13 at 21:55
  • Hi, The watchdog timer is turned off. Also, it doesn't allow me to change the delay from 100 to anything higher. I have no idea why. I found that it resets once it gets to the case statement, it outputs "FAN SPEED: 10% DC" and then resets. So im thinking the problem lies there.. – Chris Oct 02 '13 at 22:38
  • Power supply current limit is too low momentary causing too low a voltage - then reset. Raise current limit or get a better voltage supply. – chux - Reinstate Monica Oct 02 '13 at 23:39
  • Power supply is set to 12V, with 0.8A, but when the motor command is sent, the current drops to 0. Surely the circuit will only take as much current as it needs? – Chris Oct 03 '13 at 08:31

1 Answers1

0

A few suggestions,

  • Oscilliscope?
  • test with a light bulb rather than a DC motor, less current and voltage drop
  • this smells like a hardware problem
ChuckCottrill
  • 4,360
  • 2
  • 24
  • 42