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

Discussion in 'Programmer's Corner' started by valls, Apr 30, 2013.

  1. valls

    Thread Starter New Member

    Apr 30, 2013
    6
    0
    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?
    Code ( (Unknown Language)):
    1.   #include "p18f45k20.h"
    2.   #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
    3.   #define FOSC 8000000L // Using Internal Clock of 8 MHz
    4.   // Delay Function
    5.   void        _delay_us( unsigned int x) {unsigned char us;
    6.                                        us = (x)/(12000000/FOSC)|1;
    7.                                        while(--us != 0) continue; }
    8.   void _delay_ms(unsigned int ms){
    9.     unsigned char i;
    10.     if (ms == 0) return;
    11.     do {
    12.       i = 4;
    13.       do {
    14.         _delay_us(164);
    15.       } while(--i);
    16.     } while(--ms);
    17.   }
    18.   void main(void){
    19.     unsigned int ipwm;
    20.     unsigned char direction;
    21.     OSCCON=0x70;         // Select 8 Mhz internal clock
    22.     TRISC = 0x00;        // Set All on PORTC as Output
    23.     TRISA = 0b00000000;        // Input for RA0 and RA1
    24.     ANSEL = 0x01;        // Set PORT AN0 to analog input AN1 to AN7 digital I/O
    25.     ANSELH = 0x00;       // Set PORT AN8 to AN11 as Digital I/O
    26.     PORTC = 0x00;        // Turn Off all PORTC
    27.    
    28.     /* Init PWM for Full Bridge Output */
    29.     CCP1CON=0b01001100;  // Full Bridge Forward; P1A, P1C active-high; P1B, P1D active-high
    30.     CCPR1L=0;            // Start with zero Duty Cycle
    31.                  
    32.     T2CON=0b00000101;    // Postscale: 1:1, Timer2=On, Prescale = 1:4
    33.     PR2=0x65;            // Frequency: 4.90 KHz
    34.     TMR2=0;              // Start with zero Counter
    35.    
    36.     /* Init ADC */
    37.   ADCON0=0b00000000;
    38.     ADCON1=0b00000000;   // Select Left justify result. ADC port channel 0
    39.      // Select the FRC for 8 MHz
    40.     ADCON2 =0b0101011;
    41.     ADCON0bits.ADON=1;
    42.     direction=0;         // Start with Forward Direction
    43.     ipwm=0;
    44.     for(;;) {
    45.       if ( PORTAbits.RA1==1) {           // Change the Motor Direction when pressed
    46.        _delay_ms(1);
    47.        if ( PORTAbits.RA1==1) {          // Read again for simple debounce
    48.          if (direction == 0) {
    49.            direction=1;         // Reverse direction
    50.            CCP1CONbits.P1M1=1;
    51.                                 CCP1CONbits.P1M0=1;
    52.          } else {
    53.            direction=0;         // Forward direction
    54.            CCP1CONbits.P1M1=1;
    55.   CCP1CONbits.P1M0=0;
    56.   }}}
    57.       ADCON0bits.GO_DONE=1;                        // initiate conversion on the channel 0
    58.       while(ADCON0bits.GO_DONE) continue;  // Wait conversion done
    59.       ipwm = ADRESH;           // Get the highest 8 bit MSB result, ignore the 2 bit LSB
    60.       CCPR1L=ipwm;             // Set the Duty Cycle base on the ADC result
    61.   }}
    62.  
     
  2. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    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 :)
     
  3. valls

    Thread Starter New Member

    Apr 30, 2013
    6
    0
    I specified inputs.

    Code ( (Unknown Language)):
    1. 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...
     
    • enh.BMP
      File size:
      88.9 KB
      Views:
      109
  4. GopherT

    AAC Fanatic!

    Nov 23, 2012
    6,059
    3,821
    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: May 1, 2013
  5. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    Which datasheet are you reading, because the one from Microchip says that setting a bit makes it an input, which you have not done?
     
  6. valls

    Thread Starter New Member

    Apr 30, 2013
    6
    0
    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.
     
  7. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    In order to make a port, or a portion thereof, you need to set the corresponding bits. So, something like
    Code ( (Unknown Language)):
    1.  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.
     
  8. valls

    Thread Starter New Member

    Apr 30, 2013
    6
    0
    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.

    Code ( (Unknown Language)):
    1. //
    2. #include "p18f45k20.h"
    3.  
    4. #pragma config WDTEN=OFF
    5. #pragma config CPD=OFF
    6. #pragma config BOREN=OFF
    7. #pragma config IESO=OFF
    8. #pragma config CP2=OFF
    9. #pragma config FCMEN=OFF
    10. #pragma config PWRT=ON
    11. #pragma config MCLRE=OFF
    12.  
    13.  
    14. // Using Internal Clock of 8 MHz
    15.  
    16. #define FOSC 8000000L
    17.  
    18. // Delay Function
    19. void    _delay_us( unsigned int x) {unsigned char us;
    20.                us = (x)/(12000000/FOSC)|1;
    21.                while(--us != 0) continue; }
    22.  
    23. void _delay_ms(unsigned int ms)
    24. {
    25.   unsigned char i;
    26.  
    27.   if (ms == 0) return;
    28.   do {
    29.     i = 4;
    30.     do {
    31.       _delay_us(164);
    32.     } while(--i);
    33.   } while(--ms);
    34. }
    35.  
    36. void main(void)
    37. {
    38.   unsigned int ipwm;
    39.   unsigned char direction;
    40.  
    41.   OSCCON=0x70;         // Select 8 Mhz internal clock
    42.  
    43.   TRISC = 0x00;  // Set All on PORTC as Output
    44.   TRISD = 0x00;      
    45.   TRISA = 0b000000;        // Input for RA0 and RA1
    46.   ANSEL = 0x01;        // Set PORT AN0 to analog input AN1 to AN7 digital I/O
    47.   ANSELH = 0x00;       // Set PORT AN8 to AN11 as Digital I/O
    48.  
    49.  
    50.   /* Init PWM for Full Bridge Output */
    51.   CCP1CON=0b01001100;  // Full Bridge Forward; P1A, P1C active-high; P1B, P1D active-high
    52.   CCPR1L=0;            // Start with zero Duty Cycle
    53.      
    54.   T2CON=0b00000101;    // Postscale: 1:1, Timer2=On, Prescale = 1:4
    55.   PR2=0x65;            // Frequency: 4.90 KHz
    56.   TMR2=0;              // Start with zero Counter
    57.  
    58.   /* Init ADC */
    59.     ADCON0=0b00000001;
    60.   ADCON1=0b00000000;   // Select Left justify result. ADC port channel 0
    61.    // Select the FRC for 8 MHz
    62.   ADCON2 =0b00111011;
    63.  
    64.   direction=0;         // Start with Forward Direction
    65.   ipwm=0;
    66.  
    67.   for(;;)
    68. {if ( PORTAbits.RA2==1) {
    69.              
    70.      _delay_ms(1);
    71.      if ( PORTAbits.RA1==0) {      
    72.        
    73.          
    74.        
    75.          CCP1CONbits.P1M1=1;
    76.         CCP1CONbits.P1M0=1;
    77.                     }
    78.        if ( PORTAbits.RA1==1)  {
    79.                
    80.          CCP1CONbits.P1M1=0;
    81.         CCP1CONbits.P1M0=1;
    82.        }
    83.                  
    84.     ADCON0bits.GO_DONE=1;                  // initiate conversion on the channel 0
    85.     while(ADCON0bits.GO_DONE) continue;  // Wait conversion done
    86.  
    87.     ipwm = ADRESH;           // Get the highest 8 bit MSB result, ignore the 2 bit LSB
    88.     CCPR1L=ipwm;             // Set the Duty Cycle base on the ADC result
    89.  
    90.   }  
    91.   }
    92. }
    93.  
    94. /* EOF: pwm2.c */
     
    • 333.PNG
      333.PNG
      File size:
      111.2 KB
      Views:
      53
    • nh2.bmp
      File size:
      88.9 KB
      Views:
      71
  9. valls

    Thread Starter New Member

    Apr 30, 2013
    6
    0
    i get only 0.05 uA on the A output.. it could be this the problem?
     
  10. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    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.
     
  11. valls

    Thread Starter New Member

    Apr 30, 2013
    6
    0
    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?
     
  12. GopherT

    AAC Fanatic!

    Nov 23, 2012
    6,059
    3,821
    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: May 6, 2013
  13. GopherT

    AAC Fanatic!

    Nov 23, 2012
    6,059
    3,821
    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.
     
  14. marcelode1

    New Member

    May 14, 2013
    1
    0
    Hi I am trying to compile your code with mikcroC but it cannot even find the header file. Any suggestions ?
    Thanks
     
Loading...