PIC 18F45K20 c code for using PWM at a H bridge

Thread Starter

valls

Joined Apr 30, 2013
6
I'm facing with a problem in my H bridge design.

I am using PIC 18F45K20 Microchip Controller along with BJT tranzistors to make a servo direction for a 5V motor. Everything is fine but i can't get around with C code for microcontroller.

I'm using C18 Compiler.

I want to get the signal from a switch on the development bord and based on this signal i want to change the rotation sense of the motor.
Furthermore, if anybody know how i can change motor speed based upon duty cicle and a varistor placed on the development bord it will be great.

Can anyone help me with debug this code please?
Rich (BB code):
  #include "p18f45k20.h"
  #pragma config WDTEN=OFF #pragma config CPD=OFF #pragma config BOREN=OFF #pragma config IESO=OFF #pragma config CP2=OFF #pragma config FCMEN=OFF #pragma config PWRT=ON #pragma config MCLRE=OFF
  #define FOSC 8000000L // Using Internal Clock of 8 MHz
  // Delay Function
  void        _delay_us( unsigned int x) {unsigned char us; 
                                       us = (x)/(12000000/FOSC)|1; 
                                       while(--us != 0) continue; }
  void _delay_ms(unsigned int ms){
    unsigned char i;
    if (ms == 0) return;
    do {
      i = 4;
      do {
        _delay_us(164);
      } while(--i);
    } while(--ms);
  }
  void main(void){
    unsigned int ipwm;
    unsigned char direction;
    OSCCON=0x70;         // Select 8 Mhz internal clock
    TRISC = 0x00;        // Set All on PORTC as Output
    TRISA = 0b00000000;        // Input for RA0 and RA1
    ANSEL = 0x01;        // Set PORT AN0 to analog input AN1 to AN7 digital I/O
    ANSELH = 0x00;       // Set PORT AN8 to AN11 as Digital I/O
    PORTC = 0x00;        // Turn Off all PORTC
   
    /* Init PWM for Full Bridge Output */
    CCP1CON=0b01001100;  // Full Bridge Forward; P1A, P1C active-high; P1B, P1D active-high
    CCPR1L=0;            // Start with zero Duty Cycle
                 
    T2CON=0b00000101;    // Postscale: 1:1, Timer2=On, Prescale = 1:4
    PR2=0x65;            // Frequency: 4.90 KHz
    TMR2=0;              // Start with zero Counter
   
    /* Init ADC */
  ADCON0=0b00000000;
    ADCON1=0b00000000;   // Select Left justify result. ADC port channel 0
     // Select the FRC for 8 MHz
    ADCON2 =0b0101011;
    ADCON0bits.ADON=1;
    direction=0;         // Start with Forward Direction
    ipwm=0;
    for(;;) {
      if ( PORTAbits.RA1==1) {           // Change the Motor Direction when pressed
       _delay_ms(1);
       if ( PORTAbits.RA1==1) {          // Read again for simple debounce
         if (direction == 0) {
           direction=1;         // Reverse direction
           CCP1CONbits.P1M1=1;
                                CCP1CONbits.P1M0=1;
         } else {
           direction=0;         // Forward direction
           CCP1CONbits.P1M1=1;
  CCP1CONbits.P1M0=0;
  }}}
      ADCON0bits.GO_DONE=1;                        // initiate conversion on the channel 0
      while(ADCON0bits.GO_DONE) continue;  // Wait conversion done
      ipwm = ADRESH;           // Get the highest 8 bit MSB result, ignore the 2 bit LSB
      CCPR1L=ipwm;             // Set the Duty Cycle base on the ADC result
  }}
 

tshuck

Joined Oct 18, 2012
3,534
Are we supposed to know the schematic for the board you were using? Perhaps you should supply all relevant information...

What is a servo direction?

You can't do C, but have you done this in another language?

There are a couple of things that stand out at a glance:
-you have not specified any inputs, if I remember correctly, reading an analog input reads the output latch state. Make the pin the ADC us reading an input.
-You don't have your oscillator set in the configuration word, this may not default to the internal oscillator, check to be sure...

I haven't seen a do-while loop used in quite some time! Nothing wrong with that, just interesting :)
 

Thread Starter

valls

Joined Apr 30, 2013
6
I specified inputs.

Rich (BB code):
TRISA = 0b00000000;        // Input for RA0 and RA1
I attached the schema. (not very ordonated)

"Make the pin the ADC us reading an input." - i don't know going any further with code...
 

Attachments

GopherT

Joined Nov 23, 2012
8,009
Assuming your Vcc is 5 volts, the base current to your two high side transistors is only 80 microvolts (assuming 2 volt drop for your LED and 0.6v for the low side transistor Veb and 0.6v for the high side transistor = 1.8v with a 22k resistor leave only 80 micro amps)! The two low-side transistors are only seeing 100 micro amps. This is not enought to light your LEDs.

Have you tried to just get an LED o light, then get that LED to dim with PWM befor jumping to the HBridge? Start slow and simple with PICs.
 
Last edited:

tshuck

Joined Oct 18, 2012
3,534
I specified inputs.

Rich (BB code):
TRISA = 0b00000000;        // Input for RA0 and RA1
I attached the schema. (not very ordonated)

"Make the pin the ADC us reading an input." - i don't know going any further with code...
Which datasheet are you reading, because the one from Microchip says that setting a bit makes it an input, which you have not done?
 

Thread Starter

valls

Joined Apr 30, 2013
6
I don't understand what are you saying...
That datasheets are so hard to get understanded.

I have to do this for school, it's my first project with microcontrollers and i am a beginner with electronics...
Can you help me with the code? i think for you is a piece of cake.

I will really appreciate.
 

tshuck

Joined Oct 18, 2012
3,534
In order to make a port, or a portion thereof, you need to set the corresponding bits. So, something like
Rich (BB code):
 TRISD =0x02;
makes RD1 an input where the rest on port d are outputs.

Read the datasheet under the I/O Ports section, it will explain this in more detail.
 

Thread Starter

valls

Joined Apr 30, 2013
6
Ok, i managed to write the code that gives me the right signal i guess. I attached an oscilloscope printscreen and the code.

I don't know why the circuit isn.t working. The voltage on the motor is equal on - and + so i think that's the problem. This is happening because of transistors i think. I don't know how to manage this.

Are ok that resistors? the output from P1a P1b P1c p1d is 5V.
the motor is 5V and the battery attached same 5V.

What is wrong? Does it matter that additional sources that i get the signal for the on off and fwd res switches and the potentiometer? I put those for 1/0 states to control uC.

Rich (BB code):
//
#include "p18f45k20.h"

#pragma config WDTEN=OFF
#pragma config CPD=OFF
#pragma config BOREN=OFF
#pragma config IESO=OFF
#pragma config CP2=OFF
#pragma config FCMEN=OFF
#pragma config PWRT=ON
#pragma config MCLRE=OFF


// Using Internal Clock of 8 MHz

#define FOSC 8000000L

// Delay Function
void    _delay_us( unsigned int x) {unsigned char us; 
               us = (x)/(12000000/FOSC)|1; 
               while(--us != 0) continue; }

void _delay_ms(unsigned int ms)
{
  unsigned char i;

  if (ms == 0) return;
  do {
    i = 4;
    do {
      _delay_us(164);
    } while(--i);
  } while(--ms);
}

void main(void)
{
  unsigned int ipwm;
  unsigned char direction;

  OSCCON=0x70;         // Select 8 Mhz internal clock

  TRISC = 0x00;  // Set All on PORTC as Output
  TRISD = 0x00;       
  TRISA = 0b000000;        // Input for RA0 and RA1
  ANSEL = 0x01;        // Set PORT AN0 to analog input AN1 to AN7 digital I/O
  ANSELH = 0x00;       // Set PORT AN8 to AN11 as Digital I/O
 
 
  /* Init PWM for Full Bridge Output */
  CCP1CON=0b01001100;  // Full Bridge Forward; P1A, P1C active-high; P1B, P1D active-high
  CCPR1L=0;            // Start with zero Duty Cycle
      
  T2CON=0b00000101;    // Postscale: 1:1, Timer2=On, Prescale = 1:4
  PR2=0x65;            // Frequency: 4.90 KHz
  TMR2=0;              // Start with zero Counter

  /* Init ADC */
    ADCON0=0b00000001;
  ADCON1=0b00000000;   // Select Left justify result. ADC port channel 0
   // Select the FRC for 8 MHz
  ADCON2 =0b00111011;

  direction=0;         // Start with Forward Direction
  ipwm=0;

  for(;;) 
{if ( PORTAbits.RA2==1) {
              
     _delay_ms(1);
     if ( PORTAbits.RA1==0) {       
       
         
        
         CCP1CONbits.P1M1=1;
        CCP1CONbits.P1M0=1;
                    }
       if ( PORTAbits.RA1==1)  {
               
         CCP1CONbits.P1M1=0;
        CCP1CONbits.P1M0=1;
       }
                 
    ADCON0bits.GO_DONE=1;                  // initiate conversion on the channel 0
    while(ADCON0bits.GO_DONE) continue;  // Wait conversion done

    ipwm = ADRESH;           // Get the highest 8 bit MSB result, ignore the 2 bit LSB
    CCPR1L=ipwm;             // Set the Duty Cycle base on the ADC result
 
  }  
  }
}

/* EOF: pwm2.c */
 

Attachments

tshuck

Joined Oct 18, 2012
3,534
That would very much be a problem, not necessarily the problem. Read what GopherT wrote, your transistors are getting way too little current to drive them to saturation. The rule of thumb is Ib = 10% of Ic for a BJT.
 

Thread Starter

valls

Joined Apr 30, 2013
6
I clean up the wires and now its. working but i get only 1V on motor. The current on base is 13mA and whatever i put the resistor value it remain the same.... i dont understand why.

Im using Isis proteus and i get the overload CPU warning.
Also the speed on motor is quite low. when i make the changing of direction it takes very long time to hit the 0 and go backwards.

This could be the simulator fault? I dont tried the schema on real world. who can i get maximum speed on motor?
 

GopherT

Joined Nov 23, 2012
8,009
Yes, for Q3 and Q2, look at the path driving those transistors. The PIC outputs 4.5 volts, the LED going to Q3 causes that voltage to drop to 2.5 (e.g. red LED), then the 0.6V emitter-base voltage drop of Q3 brings you down to 1.9 volts. THAT IS FOR YOUR HIGH-SIDE Q3 DRIVER TRANSISTOR. That is where all of your voltage was lost.

Now your low side, Q1 will be at 0.6V above ground. Total for your motor will be 1.9 - 0.6 volts or 1.3 at very best case. The high resistance into the transistor bases and provides very little current. That is why you are not even getting 1.3 volts but 1 volt.

Some suggestions,
1) get rid of the LEDs on the Base of your H-BRIDGE transistors, that will give you two volts more than you have.
2) Use MOSFETs instead of BJTs (that will allow you to avoid the 0.6 volt emitter base drop at each transistor
3) use Vcc higher than 5 volts.
 
Last edited:

GopherT

Joined Nov 23, 2012
8,009
Also use resistors as small as 220 ohm to connect your pic to the transistor bases (or according to suggestion in post #10.

Finally, consider making a bridge from both n and p MOSFETS. P for high side and n for low side. In that case, keep pic pins high when you want the p-type MOSFETS to stay off.
 
Top