PIC16F877A needs help ASAP :(

Thread Starter

AyieJosh

Joined Oct 17, 2013
5
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.
 

Attachments

JohnInTX

Joined Jun 26, 2012
4,787
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:

Thread Starter

AyieJosh

Joined Oct 17, 2013
5
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
 

JohnInTX

Joined Jun 26, 2012
4,787
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:
Rich (BB code):
#define SN1 PORTB.F0
#define LED1 PORTC.F0
#define LED2 PORTC.F1
#define M1_POS PORTC.F4
#define M1_NEG PORTC.F5
#define M2_POS PORTC.F6
#define M2_NEG PORTC.F7

void main(void)
{
 TRISB = 0b00000000;
 PORTB = 0b00000000;
 TRISC = 0b11111111;
 PORTC = 0b11111111;

 while(1)
 {
  if (SN1==1)
  {
   LED1 = 1;
   LED2 = 1;
   M1_POS = 1;
   M1_NEG = 0;
   M2_POS = 1;
   M2_NEG = 0;
   Delay_ms(50);
  }

  if (SN1==0)
  {
   LED1 = 0;
   LED2 = 0;
   M1_POS = 0;
   M1_NEG = 1;
   M2_POS = 0;
   M2_NEG = 1;
   Delay_ms(50);
  }

  else

  {
   PORTC = 0x00;
  }
 }
}
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.

Rich (BB code):
/* First, set ADCONx to configure the port pins as digital.. lots of beginners forget this but it's necessary */
ADCON1 = 0b00000110 // configure all IO to digital (not analog)
ADCON0 = 0x00; // kill the ADC (its done in reset but I like to be sure)

/* 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 */
PORTA = 0x00;  
PORTB = 0x01; // I like to keep the input f/f at 1
PORTC = 0x00;
PORTD = 0x00;
PORTE = 0x00;
/* Then set the TRIS to configure the ports.. Make ALL unused pins OUTPUT-0. Do not let them just float... */
TRISA = 0x00;
TRISB = 0x01; //RB0 is the only input
TRISC = 0x00;
TRISD = 0x00;
TRISE = 0x00;
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:

Thread Starter

AyieJosh

Joined Oct 17, 2013
5
1)
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.
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' ?
Rich (BB code):
#define M1_POS PORTB.F0  //
#define M1_NEG PORTB.F1  //
#define M2_POS PORTB.F2  //
#define M2_NEG PORTB.F3  //
#define LED1 PORTA.F0    //
#define LED2 PORTA.F1    //
#define LED3 PORTA.F2    //
#define LED4 PORTA.F3    //
#define LED5 PORTC.F3    //
#define LED6 PORTA.F5    //
#define LED7 PORTC.F4    //
#define LED8 PORTC.F5    //
#define LED9 PORTC.F6    //
#define LED10 PORTC.F7   //
#define SNSR PORTD.F2    //

void main()
{
  short duty  = 0; //initial value for duty

  ADCON1 = 0x06;// To turn off ADC
  CMCON = 0x07; // To turn off comparators
  TRISD = 0xFF; //PORTD as input
  TRISC = 0x00; //PORTC as output (PWMs)
  TRISB = 0x00; //PORTB as output (MOTORs)
  TRISA = 0x00; //PORTA as output (LEDs)
  PORTB = 0x02; //Run motor in anticlock wise

  PWM1_Init(1000);  //Initialize PWM1
  PWM1_Start();  //start PWM1
  PWM1_Set_Duty(duty); //Set current duty for PWM1

  while (1)        // endless loop
  {
     if (!RD0_bit && duty<50) //if button on RD0 pressed
     {
        Delay_ms(40);
        duty = duty + 10;  //increment current_duty
        PWM1_Set_Duty(duty);  //Change the duty cycle
     }
     if (!RD1_bit && duty >0) //button on RD1 pressed
     {
       Delay_ms(40);
       duty = duty - 10;  //decrement duty
       PWM1_Set_Duty(duty);
     }
    Delay_ms(10);      // slow down change pace a little
    if (SNSR==1)
    {
   //To turn motor clockwise
   M1_POS = 1;
   M2_POS = 1;
   LED1 = 0;
   LED2 = 0;
   Delay_ms(60);//20 miliseconds delay

   //To Stop motor
   M1_POS = 0; // or PORTB = 3
   M2_POS = 0;
   LED1 = 0;
   LED2 = 0;
   Delay_ms(100);//0.5 seconds delay

   //To turn motor anticlockwise direction
   M1_NEG = 1;
   M2_NEG = 1;
   LED1 = 0;
   LED2 = 0;
   Delay_ms(60);//20 miliseconds delay

   //To turn motor anticlockwise direction
   M1_NEG = 0;
   M2_NEG = 0;
   LED1 = 0;
   LED2 = 0;
   Delay_ms(100);//0.5 seconds delay
     }
     
   if (SNSR==1)
   { //Running Light LEDs
    LED1= 1;
    Delay_ms(50);
    LED2= 1;
    Delay_ms(50);
    LED1 = 0;
    Delay_ms(50);
    LED3= 1;
    Delay_ms(50);
    LED2 = 0;
    Delay_ms(50);
    LED4= 1;
    Delay_ms(50);
    LED3 = 0;
    Delay_ms(50);
    LED5 = 1;
    Delay_ms(50);
    LED4 = 0;
    Delay_ms(50);
    LED6= 1;
    Delay_ms(50);
    LED5 = 0;
    Delay_ms(50);
    LED7= 1;
    Delay_ms(50);
    LED6 = 0;
    Delay_ms(50);
    LED8 = 1;
    Delay_ms(50);
    LED7 = 0;
    Delay_ms(50);
    LED9 = 1;
    Delay_ms(50);
    LED8 = 0;
    Delay_ms(50);
    LED10 = 1;
    Delay_ms(50);
    LED9 = 0;
    Delay_ms(50);
    LED10 = 0;
    Delay_ms(20);
    }
    
   }
 }
 

Attachments

Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
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?

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' ?
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!
 
Top