PIC16F877A needs help ASAP :(

Discussion in 'Embedded Systems and Microcontrollers' started by AyieJosh, Oct 17, 2013.

  1. AyieJosh

    Thread Starter New Member

    Oct 17, 2013
    5
    0
    hey im using PIC16F877A to power the Motor that requires 12V Output power. the problem is the output is 5V maybe less. anyone have solution to boost it into 12V ? and i made a program for the PIC but seems that the program fails to simulate as i wanted to. the push button would be the infrared sensor that when IR is 'ON' the motor will rotate 90 degrees. both of the motors. i have include the schematic diagram of mine and the programming files. please and please help me with this. im so desperate to make this work.. TQ!

    PS: the motor will rotate 90degree then rotate back to its original position when the 'IR' was triggered. when the Motor is activated, those 2 LED will lights up and lights out when the motor is rotate back.
     
  2. MrChips

    Moderator

    Oct 2, 2009
    12,429
    3,360
    You cannot drive a 12V motor directly from an mcu. Use a transistor to switch 12V power to the motor.
     
  3. slakku

    New Member

    Jul 27, 2011
    3
    0
    Hello AyieJosh,

    We cannot drive the 12V Motor directly with the Micro-controller.
    Possible solution could be
    --- Use Gate drivers in between MCU and Motor OR
    --- Use Mosfet to switch 12V.
     
  4. JohnInTX

    Moderator

    Jun 26, 2012
    2,341
    1,024
    In your code:

    TRISB and TRISC are wrong. '0' makes an Output, '1' makes an input.

    You have not set any CONFIG flags to specify the oscillator type, frequency etc.

    There are other ports that are not initialized. Always initialize the part COMPLETELY. While not a problem here, ADCON1 should always be initialized to make the ports digital if you are not using the ADC.

    As the others have said, you can't drive a 12V motor from a 5V pin. Your code shows a push-pull reversing scheme so you are looking at some sort of 'H-bridge' to drive the motor. Microchip has several application notes describing how to drive motors as well as interface chips to do it.

    Good luck!
     
    Last edited: Oct 17, 2013
  5. AyieJosh

    Thread Starter New Member

    Oct 17, 2013
    5
    0
    could anyone attach the schematic to drive the 5v into 12v? btw, i manage to make the circuit run as i want as a test programming.. now i just want to make the motor to rotates 90degrees then reverse back to original position..

    about the programming, could you show which is wrong? just a few correcting would be good enuff for me to understand it. thanks :D
     
  6. AyieJosh

    Thread Starter New Member

    Oct 17, 2013
    5
    0
    atleast the gate drive please? i only need the schematic for the output to become 12v from 5v. please...
     
  7. nerdegutta

    Moderator

    Dec 15, 2009
    2,515
    785
    Perhaps this will help a bit...

    npn as a switch
     
  8. JohnInTX

    Moderator

    Jun 26, 2012
    2,341
    1,024
    1) Multiple threads on the same problem are discouraged if not moderated off. Keeping things in one place will help us help you.
    2) Post your code using CODE tags. That way everyone can see what's going on. Unzipping source files is a beating. So here's your code:
    Code ( (Unknown Language)):
    1. #define SN1 PORTB.F0
    2. #define LED1 PORTC.F0
    3. #define LED2 PORTC.F1
    4. #define M1_POS PORTC.F4
    5. #define M1_NEG PORTC.F5
    6. #define M2_POS PORTC.F6
    7. #define M2_NEG PORTC.F7
    8.  
    9. void main(void)
    10. {
    11.  [B]TRISB = 0b00000000[/B];
    12.  PORTB = 0b00000000;
    13.  [B]TRISC = 0b11111111;[/B]
    14.  PORTC = 0b11111111;
    15.  
    16.  while(1)
    17.  {
    18.   if (SN1==1)
    19.   {
    20.    LED1 = 1;
    21.    LED2 = 1;
    22.    M1_POS = 1;
    23.    M1_NEG = 0;
    24.    M2_POS = 1;
    25.    M2_NEG = 0;
    26.    Delay_ms(50);
    27.   }
    28.  
    29.   if (SN1==0)
    30.   {
    31.    LED1 = 0;
    32.    LED2 = 0;
    33.    M1_POS = 0;
    34.    M1_NEG = 1;
    35.    M2_POS = 0;
    36.    M2_NEG = 1;
    37.    Delay_ms(50);
    38.   }
    39.  
    40.   else
    41.  
    42.   {
    43.    PORTC = 0x00;
    44.   }
    45.  }
    46. }
    As indicated in bold above, you have your TRIS direction backwards. Fix that first while you initialize all I/O. RB0 is an input. Everything else on your schematic is an output. Initialize the ports first and make all unused pins OUTPUT 0.

    Code ( (Unknown Language)):
    1. /* First, set ADCONx to configure the port pins as digital.. lots of beginners forget this but it's necessary */
    2. ADCON1 = 0b00000110 // configure all IO to digital (not analog)
    3. ADCON0 = 0x00; // kill the ADC (its done in reset but I like to be sure)
    4.  
    5. /* set the port bits before the TRIS to avoid transients when coming out of HiZ (from RESET)...  I use 0x00 because its late and I'm tired.  I think the preferred way is in binary as you have it shown */
    6. PORTA = 0x00;  
    7. PORTB = 0x01; // I like to keep the input f/f at 1
    8. PORTC = 0x00;
    9. PORTD = 0x00;
    10. PORTE = 0x00;
    11. /* Then set the TRIS to configure the ports.. Make ALL unused pins OUTPUT-0. Do not let them just float... */
    12. TRISA = 0x00;
    13. TRISB = 0x01; //RB0 is the only input
    14. TRISC = 0x00;
    15. TRISD = 0x00;
    16. TRISE = 0x00;
    17.  
    NEXT:
    You must set the CONFIG bits to specify the oscillator and other things. Look at chapter 14 of the datasheet. You must look at and specify every option described. Neither your code nor schematic provides any info for us here. Inspect the option bits and include them in the source code.

    Of special note is the oscillator. The 16F877 does not have an internal oscillator so you must provide one at OSC1/2. You do not have one so the code won't run at all. When you add one, you will have to tell the compiler what its frequency is so that it can calculate the delays based on that frequency.

    Your basic logic is OK but as you already know, you will need to add some sort of driver for the motor as the PIC cannot drive it directly.
     
    Last edited: Oct 17, 2013
    AyieJosh likes this.
  9. AyieJosh

    Thread Starter New Member

    Oct 17, 2013
    5
    0
    Hi JohnInTX, i already made a code that i wanted it to become. I'll attach the files for you to check it. the problem that i faced is that the process doesnt run in the same time.. like the LED was running all the time so that the motor part need to wait the LEDs process to end then the motor can started.. is it possible to make it 'Multi-Tasking' ?
    Code ( (Unknown Language)):
    1.  
    2. #define M1_POS PORTB.F0  //
    3. #define M1_NEG PORTB.F1  //
    4. #define M2_POS PORTB.F2  //
    5. #define M2_NEG PORTB.F3  //
    6. #define LED1 PORTA.F0    //
    7. #define LED2 PORTA.F1    //
    8. #define LED3 PORTA.F2    //
    9. #define LED4 PORTA.F3    //
    10. #define LED5 PORTC.F3    //
    11. #define LED6 PORTA.F5    //
    12. #define LED7 PORTC.F4    //
    13. #define LED8 PORTC.F5    //
    14. #define LED9 PORTC.F6    //
    15. #define LED10 PORTC.F7   //
    16. #define SNSR PORTD.F2    //
    17.  
    18. void main()
    19. {
    20.   short duty  = 0; //initial value for duty
    21.  
    22.   ADCON1 = 0x06;// To turn off ADC
    23.   CMCON = 0x07; // To turn off comparators
    24.   TRISD = 0xFF; //PORTD as input
    25.   TRISC = 0x00; //PORTC as output (PWMs)
    26.   TRISB = 0x00; //PORTB as output (MOTORs)
    27.   TRISA = 0x00; //PORTA as output (LEDs)
    28.   PORTB = 0x02; //Run motor in anticlock wise
    29.  
    30.   PWM1_Init(1000);  //Initialize PWM1
    31.   PWM1_Start();  //start PWM1
    32.   PWM1_Set_Duty(duty); //Set current duty for PWM1
    33.  
    34.   while (1)        // endless loop
    35.   {
    36.      if (!RD0_bit && duty<50) //if button on RD0 pressed
    37.      {
    38.         Delay_ms(40);
    39.         duty = duty + 10;  //increment current_duty
    40.         PWM1_Set_Duty(duty);  //Change the duty cycle
    41.      }
    42.      if (!RD1_bit && duty >0) //button on RD1 pressed
    43.      {
    44.        Delay_ms(40);
    45.        duty = duty - 10;  //decrement duty
    46.        PWM1_Set_Duty(duty);
    47.      }
    48.     Delay_ms(10);      // slow down change pace a little
    49.     if (SNSR==1)
    50.     {
    51.    //To turn motor clockwise
    52.    M1_POS = 1;
    53.    M2_POS = 1;
    54.    LED1 = 0;
    55.    LED2 = 0;
    56.    Delay_ms(60);//20 miliseconds delay
    57.  
    58.    //To Stop motor
    59.    M1_POS = 0; // or PORTB = 3
    60.    M2_POS = 0;
    61.    LED1 = 0;
    62.    LED2 = 0;
    63.    Delay_ms(100);//0.5 seconds delay
    64.  
    65.    //To turn motor anticlockwise direction
    66.    M1_NEG = 1;
    67.    M2_NEG = 1;
    68.    LED1 = 0;
    69.    LED2 = 0;
    70.    Delay_ms(60);//20 miliseconds delay
    71.  
    72.    //To turn motor anticlockwise direction
    73.    M1_NEG = 0;
    74.    M2_NEG = 0;
    75.    LED1 = 0;
    76.    LED2 = 0;
    77.    Delay_ms(100);//0.5 seconds delay
    78.      }
    79.      
    80.    if (SNSR==1)
    81.    { //Running Light LEDs
    82.     LED1= 1;
    83.     Delay_ms(50);
    84.     LED2= 1;
    85.     Delay_ms(50);
    86.     LED1 = 0;
    87.     Delay_ms(50);
    88.     LED3= 1;
    89.     Delay_ms(50);
    90.     LED2 = 0;
    91.     Delay_ms(50);
    92.     LED4= 1;
    93.     Delay_ms(50);
    94.     LED3 = 0;
    95.     Delay_ms(50);
    96.     LED5 = 1;
    97.     Delay_ms(50);
    98.     LED4 = 0;
    99.     Delay_ms(50);
    100.     LED6= 1;
    101.     Delay_ms(50);
    102.     LED5 = 0;
    103.     Delay_ms(50);
    104.     LED7= 1;
    105.     Delay_ms(50);
    106.     LED6 = 0;
    107.     Delay_ms(50);
    108.     LED8 = 1;
    109.     Delay_ms(50);
    110.     LED7 = 0;
    111.     Delay_ms(50);
    112.     LED9 = 1;
    113.     Delay_ms(50);
    114.     LED8 = 0;
    115.     Delay_ms(50);
    116.     LED10 = 1;
    117.     Delay_ms(50);
    118.     LED9 = 0;
    119.     Delay_ms(50);
    120.     LED10 = 0;
    121.     Delay_ms(20);
    122.     }
    123.    
    124.    }
    125.  }
     
    Last edited: Oct 18, 2013
  10. JohnInTX

    Moderator

    Jun 26, 2012
    2,341
    1,024
    I see you have the motor drivers installed and presumably they are working. I won't run through all of your code since you are unhappy with the delays (no surprise there) and you'll be changing it. Before we get to that, you still have some unconnected pins as inputs. For example TRISD is 0xFF which sets all pins to input. Since RD3-RD7 are unconnected, set those to outputs i.e. TRISD = 0b00000111 and PORTD = 0b00000111. This will set the unused pins to output a 0. Do the same on other ports with unconnected pins.

    No CONFIG settings yet?

    Yeah. I never use dumb delays because they wind up doing what is happening to you i.e. all of your CPU time is burned counting off delays and you can't do anything else. So.... multitasking? That would work; it's what I use in some form or other on everything from a 10Fxxx up mostly hand-rolled but some commercial stuff on bigger chips.

    You can solve lots of these problems by organizing your code differently and designing the functions so that they NEVER wait for things like timing an LED. Instead, when a function knows it has to wait (another 25ms to go before turning the LED off) it returns and something else runs.

    Start by creating a system TIK i.e. a timer that interrupts the processor every 1ms or so. On 16F, I'd probably use TMR2/PR2 because once its set up, it runs without reloading. Declare timer variables for EACH independent function i.e. if three LEDs flash at different times/rates, each will need its own variable. Keep the timer vars 1 byte if possible. On each sysTIK (TMR2IF), inspect EACH timer var and if it is non ZERO, decrement it. Leave it alone if it IS zero.

    To flash an LED load its timer with some number of TIKS, turn on the LED then return. Periodically inspect the timer by calling the routine from the main loop and when the timer has run to zero turn the LED off. In between inspecting the timer, you have time to do other things. Your main loop will contain a section that repeatedly calls the functions associated with each function (LED, debounce buttons etc) with no lost time in delays.

    More complex functions are usually implemented in some kind of state-machine. Each time the function runs, it performs some action based on its state. The state is updated as the function's sequence progresses.
    For a motor you might have:
    State 0 - OFF
    State 1 - run clockwise until it hits a switch.
    State 2 - OFF, at switch
    State 3 - run CCW until it hits switch 2.
    State 4 - OFF, at switch 2.
    To use it, you would load state 1 to start the motor. Calling the routine repeatedly would re-run state 1 looking for the switch. When at the switch, change the state to 2. etc. etc. Note that 'waiting' to hit the switch does not cause the CPU to stall there waiting for the switch. The state-machine is called and returns immediately if it has nothing else to do

    There's a bit more to it and certainly other ways to do it but the main theme stays the same, the CPU never waits on some long process, it gets released and then comes back periodically to check on things.

    A simple approach like this won't solve all problems like this but you could check out FreeRTOS etc. for some solutions. One caveat, the 16Fxxx is not particularly well suited for many traditional RTOS approaches because of its limited resources but your project would fit well into some sort of scheme like I have described.

    Give it some thought. May have a simple framework somewhere that would work but its not hard to write something like I have described.

    Have fun!
     
Loading...