Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Pic 16f877 CCS

Status
Not open for further replies.

AboudaKing

Member level 1
Joined
May 22, 2019
Messages
37
Helped
0
Reputation
0
Reaction score
1
Trophy points
8
Activity points
234
Im working on small project using PIC16f877 with 2 PIR sensor
The purpose of my project is automatic stairs light
My project and code works fine except one part that i could not figure it out
Well one PIR sensor in buttom staire nd other one on top when you going up the light start lighting up the way stairs by staire with 100ms delay in between
That works good both ways up/down
But if smone going up and other one going down it lights only in one way 'first one who passed'
Basicly once the PIC start the sensor loop
(PIR_1 LIGHTS WAY UP - PIR_2 LIGHTS WAY DOWN )
it cant start the 2nd loop untill first one complets all lights on then all off' only then it starts reading from sensors again
By that the code is not functioning well .

any solution so the PIC excute both loops incase both sensors were activated knowing that i have already tried free RTOS and didnt work for me
Thank you
 

This sounds like you need to create a state machine and then work through that with pencil and paper first.
Once you know how to transition between the various conditions, then you can start the coding.
I don't think it will be terribly complex but an RTOS sounds like significant overkill to me.
Susan
 

I agree with Susan. It seems you are starting some loop to turn the lights on in sequence and while in that loop you are blocking other operations. RTOS in such a PIC would cause more problems because of the small memory available.

As an alternative to a state machine, you could configure interrupts to maintain two or more timers and trigger them from the sensors at each end. The program can then check the timers and operate the lights while the timing works as a separate process.

We need to see what you have done so far.

Brian.
 

Code:
#include <satairs final.h>

#define CAP_1 INPUT(PIN_A0)    //////first sensor
#define CAP_2 INPUT(PIN_A1)    //////second sensor
void main()
{
   while(TRUE)
   {
      if (CAP_1==1)          ///// sensor 1 =1
      {
      output_high(PIN_B0);   //// turning on lights
      delay_ms(100);
      output_high(PIN_B1);
      delay_ms(100);
      output_high(PIN_B2);
      delay_ms(100);
      output_high(PIN_B3);
      delay_ms(100);
      output_high(PIN_B4);
      delay_ms(100);
      output_high(PIN_B5);
      delay_ms(100);
      output_high(PIN_B6);
      delay_ms(100);
      output_high(PIN_B7);
      delay_ms(100);
      output_high(PIN_D7);
      delay_ms(100);
      output_high(PIN_D6);
      delay_ms(100);
      output_high(PIN_D5);
      delay_ms(100);
      output_high(PIN_D4);
      delay_ms(100);
      output_high(PIN_C7);
      delay_ms(100);
      output_high(PIN_C6);
      delay_ms(100);
      output_high(PIN_C5);
      delay_ms(100);
      output_high(PIN_C4);
      delay_ms(100);
      output_high(PIN_D3);
      delay_ms(100);
      output_high(PIN_D2);
      delay_ms(100);
      output_high(PIN_D1);
      delay_ms(100);
      output_high(PIN_D0);
      delay_ms(1000);
      /////////////////////////////////// turning OFF lights
      output_low(PIN_B0);
      delay_ms(100);
      output_low(PIN_B1);
      delay_ms(100);
      output_low(PIN_B2);
      delay_ms(100);
      output_low(PIN_B3);
      delay_ms(100);
      output_low(PIN_B4);
      delay_ms(100);
      output_low(PIN_B5);
      delay_ms(100);
      output_low(PIN_B6);
      delay_ms(100);
      output_low(PIN_B7);
      delay_ms(100);
      output_low(PIN_D7);
      delay_ms(100);
      output_low(PIN_D6);
      delay_ms(100);
      output_low(PIN_D5);
      delay_ms(100);
      output_low(PIN_D4);
      delay_ms(100);
      output_low(PIN_C7);
      delay_ms(100);
      output_low(PIN_C6);
      delay_ms(100);
      output_low(PIN_C5);
      delay_ms(100);
      output_low(PIN_C4);
      delay_ms(100);
      output_low(PIN_D3);
      delay_ms(100);
      output_low(PIN_D2);
      delay_ms(100);
      output_low(PIN_D1);
      delay_ms(100);
      output_low(PIN_D0);
      delay_ms(100);

      }
      else if(CAP_2==1)        //////sensor 2 =1
      {    
      output_high(PIN_D0);     /// turning ON lights
      delay_ms(100);
      output_high(PIN_D1);
      delay_ms(100);
      output_high(PIN_D2);
      delay_ms(100);
      output_high(PIN_D3);
      delay_ms(100);
      output_high(PIN_C4);
      delay_ms(100);
      output_high(PIN_C5);
      delay_ms(100);
      output_high(PIN_C6);
      delay_ms(100);
      output_high(PIN_C7);
      delay_ms(100);
      output_high(PIN_D4);
      delay_ms(100);
      output_high(PIN_D5);
      delay_ms(100);
      output_high(PIN_D6);
      delay_ms(100);
      output_high(PIN_D7);
      delay_ms(100);
      output_high(PIN_B7);
      delay_ms(100);
      output_high(PIN_B6);
      delay_ms(100);
      output_high(PIN_B5);
      delay_ms(100);
      output_high(PIN_B4);
      delay_ms(100);
      output_high(PIN_B3);
      delay_ms(100);
      output_high(PIN_B2);
      delay_ms(100);
      output_high(PIN_B1);
      delay_ms(100);
      output_high(PIN_B0);
      delay_ms(1000);
      //////////////////////////// turning OFF lights
      output_low(PIN_D0);
      delay_ms(100);
      output_low(PIN_D1);
      delay_ms(100);
      output_low(PIN_D2);
      delay_ms(100);
      output_low(PIN_D3);
      delay_ms(100);
      output_low(PIN_C4);
      delay_ms(100);
      output_low(PIN_C5);
      delay_ms(100);
      output_low(PIN_C6);
      delay_ms(100);
      output_low(PIN_C7);
      delay_ms(100);
      output_low(PIN_D4);
      delay_ms(100);
      output_low(PIN_D5);
      delay_ms(100);
      output_low(PIN_D6);
      delay_ms(100);
      output_low(PIN_D7);
      delay_ms(100);
      output_low(PIN_B7);
      delay_ms(100);
      output_low(PIN_B6);
      delay_ms(100);
      output_low(PIN_B5);
      delay_ms(100);
      output_low(PIN_B4);
      delay_ms(100);
      output_low(PIN_B3);
      delay_ms(100);
      output_low(PIN_B2);
      delay_ms(100);
      output_low(PIN_B1);
      delay_ms(100);
      output_low(PIN_B0);
      delay_ms(100);    
      }
   }
}
We need to see what you have done so far.
 

Thank you. The code confirms what I suspected. As soon as "if (CAP_1==1)" is true you enter a blocking routine that stops anything else being checked and you don't leave it for several seconds. The same for CAP_2.

I suggest you look at using timer interrupts to create 100ms delays, they work the same way as the 'delay_ms(100)' function but the timer runs in the background, leaving the main() loop to run at full speed. You can then use the value set by the counter to decide which pin goes high and low and if necessary reverse the direction at any time or change the sequence.

See if you can create an interrupt routine that is triggered by a timer (suggest TMR1) that increments a variable every 100ms and post the code so we can see how you did it.

I see another problem in your project, it has no way know which direction someone is passing the PIR. Suppose someone starts at the CAP_1 end and starts the sequence, I would guess they eventually get to the other end and pass the CAP_2 sensor which starts it over again. Consider what happens if someone turns around on the stairs or what would happen if two people were on the stair together, possibly going opposite ways.

Brian.
 
Last edited:

Thank you. The code confirms what I suspected. As soon as "if (CAP_1==1)" is true you enter a blocking routine that stops anything else being checked and you don't leave it for several seconds. The same for CAP_2.

I suggest you look at using timer interrupts to create 100ms delays, they work the same way as the 'delay_ms(100)' function but the timer runs in the background, leaving the main() loop to run at full speed. You can then use the value set by the counter to decide which pin goes high and low and if necessary reverse the direction at any time or change the sequence.

See if you can create an interrupt routine that is triggered by a timer (suggest TMR1) that increments a variable every 100ms and post the code so we can see how you did it.

I see another problem in your project, it has no way know which direction someone is passing the PIR. Suppose someone starts at the CAP_1 end and starts the sequence, I would guess they eventually get to the other end and pass the CAP_2 sensor which starts it over again. Consider what happens if someone turns around on the stairs or what would happen if two people were on the stair together, possibly going opposite ways.

Brian.
i'll try what you have suggested (timer) and post my new code when i'm done with it

by solving that problem i'm gonna face the one you mentioned about knowing which direction person is going
ill solve first problem first when i'm done with it i'll see what and how exactly second problem is and try to solve.
as start it seems i'll have to use 'logic' between both sensors as condition for the sequences
 

I suggest you look at using timer interrupts to create 100ms delays,
I managed to make code that is based on timer1 which is 500ms turning on/off LED 'toggle'
but I couldn't manage to edit it so I can apply it in my original code
I can say that I still don't understand how to apply timer1 so it work instead of 'delay'
is it gonna be like calling sub_function as assembly ? or how exactly I'm gonna replace 'delay' with timer
PS: code bellow was the only working for me I'm using CCS compiler
--- Updated ---

Code:
#include <RTOS.h>
#use delay(crystal=4000000)
#define but_1 INPUT(PIN_A0)
#define but_2 INPUT(PIN_A1)
#INT_TIMER1
void loop_1(void)
{
     clear_interrupt(INT_TIMER1);
     output_toggle(PIN_B0);
     set_timer1(3036);
}
void main()
{
   setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_8 ); // Internal clock and prescaler 8
   set_timer1(3036);                            // Preload value
   clear_interrupt(INT_TIMER1);                 // Clear Timer1 interrupt flag bit
   enable_interrupts(INT_TIMER1);               // Enable Timer1 interrupt
   enable_interrupts(GLOBAL);                   // Enable global interrupts
   output_low(PIN_B0);
 
   while(TRUE) ;
}
 

Hi,

an interrupt is a special feature of a microcontroller. It is not general. Thus you need to to read (each) the microcontroller datasheet how it works.

An interrupt stops the processing in main() loop and processes the according ISR. There may be many interrupts in a microcontroller and thus there may be many ISRs. But you need to tell the microcontoller wich ISR you want to run.

your "loop_1":
* neither is a loop
* nor follows naming conventions for ISRs

You need to read the documentation: Usually an timer1 ISR has to be named "ISR( TIMER1_COMPA_vect )" (for an AVR). You must not modifiy this name, else the Interrupt can´t be processed.

Klaus
 

The concept of interrupts seems scary if you don't understand how they work but they are really quite simple and incredibly useful. Think of an interrupt routine (an 'ISR') as a completely different program to the one in the main() loop and it is started by a hardware trigger. When it finishes running, it shuts down and returns control to the main() program where it left off. The main() program may not even be aware the ISR is there at all but usually one or more variables are shared so they can interact with each other. You NEVER call an ISR in software, at least on PIC devices, you set up the conditions for it to be triggered, enable it then leave it alone. The hardware event forces the ISR to run, in your case the event is TMR1 rolling over from maximum value of 0xFFFF to zero.

So firstly, you need to write the ISR and as Klaus explained, there is a special way of naming it so the compiler knows to place it in the reserved memory space. Then you need to do something in the ISR, most likely in your case it would be to re-load TMR1 so it repeats the same count and rolls over after the correct time. Note that you must do this inside the ISR or after the first time it is called it will do a full count up from zero before it interrupts again. Then do whatever is necessary to service the interrupt and finally exit from it. A word of caution, if you change a variable inside the ISR that you also use in the main() program, declare it as 'volatile', this is a hint to the compiler that it shouldn't trust any copies of the variable it has made because the value might have been changed unexpectedly by the ISR. NEVER,NEVER,NEVER use delays inside the ISR, they probably won't work anyway but you should aim to leave the ISR as quickly as possible.

I suggest once you have written the ISR, you keep a variable inside it that you increment each time it is called. So for example, if your variable was called "StepNumber", you would add the line "StepNumber++;" inside the ISR code. Now if TMR1 triggers the interrupt every 100mS, the value in "StepNumber" will increase by one every 100mS and it will happen without using any delay routines. After that, you can change your code so that the pins check the value in "StepNumber" to see if they should be high or low. Note that you can put a new value in "StepNumber" or clear it at any time if you want to.

Brian.
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top