|
|
View previous topic :: View next topic |
Author |
Message |
CCSNewbie
Joined: 15 May 2008 Posts: 12
|
One problem solved, two more to go (Counters and timers) |
Posted: Thu May 15, 2008 7:09 am |
|
|
Hi guys first of all thanks for taking the time to read this thread.
I have searched the entire forums and although i found some codes that could assist me in my problem i still could not put the pieces together. I'm not so much of an expert when it comes to coding in CCS.
I will try to explain my situation as detailed as i could.
Basically i'm trying to build an automated pedestrian crossing system in which the pedestrian does not need to press the button to cross the road.
I am using PIC16F877A this time around and it will be hooked to a couple of sensors and some output LEDs.
-----------------------------------------------------------------------------------
What i will by setting up is a mini traffic lights circuit which has 3 inputs sensors (2 to detect pedestrians, one more to detect the traffic) connected to PIN_A0, PIN_A1, PIN_A2. These will be connected to reflective sensors to detect the presence of pedestrians and cars.
There are 4 outputs namely B0,B1,B2, B3 at the traffic lights.
Assume
B0 = Green 1,
B1 =Yellow 1,
B2 =Red 1
B3 =additional blinking light
Condition 1.
What my program needs to do is, each time PIN_A0 and PIN_A1 hits high, their individual counter will increment by 1. This is to detect the amount of cars and pedestrians alike.
Condition 2.
When PIN_A2 is HIGH for more than say, 10 seconds non stop, it will call a function that will make the lights go yellow for 4 secs, then red for a duration which is determined by (5+ Value of CARSENS/Value of PEDSENS1) seconds
-----------------------------------------------------------
I've read that i am not supposed to use delays and utilize interrupts instead as delays makes the programs unresponsive.
Q1) So how do i use interrupts in this program?
Q2) How should i call the functions each time an interrupt(time cycle) occurs?
Q3)What if as the lights turn yellow (after PIN_A2 is high >10 seconds), i want to have an additional blinking lights? Without using delay, how do i make it blink on/off at 1s intervals?
After the red light duration is over, the counters will reset and the loop will repeat itself again.
This is just a brief idea of what i will be doing. There's actually a lot more to it but if it will help to kick-start my CCS days :D
Thanks guys!!
Last edited by CCSNewbie on Mon May 19, 2008 2:31 pm; edited 1 time in total |
|
|
RLScott
Joined: 10 Jul 2007 Posts: 465
|
Re: Difficulties in setting up a counter,timer and Interrupt |
Posted: Thu May 15, 2008 9:12 am |
|
|
I don't know how reliable your sensors are, but you almost certainly will have to do a significant amount of debouncing on the inputs. It is likely that a single pedestrian might cause the input pin to go high and low a few hundred times. You can't just count transitions and expect that it will give you a reliable indication of counting pedestrians.
Quote: |
...I've read that i am not supposed to use delays and utilize interrupts instead as delays makes the programs unresponsive...
|
That may be true as a general rule, but there are exceptions. Interrupts are not the cure for everything. A properly designed Big Polling Loop can work just fine for an application such as yours that does not need especially fast response time.
Quote: |
...So how do i use interrupts in this program?..
|
I would say that the most useful application of interrupts in your program would be to manage the blinking of the LEDs. Use timer interrupts.
Quote: |
...How should i call the functions each time an interrupt(time cycle) occurs?...
|
You don't call main functions from within your interrupt code. What you do is make your interrupt code as short as possible so that it returns immediately to the main program when it is done. Think of the interrupt code as a separate intelligence that wakes up every once in a while, does something, then goes back to sleep. If you use interrupts to blink LEDs as I suggested, then there will be no communcation from the interrupt code to the main code. The communication would go the other way. The main code sets some variables that affects what the interrupt code does.
Quote: |
..This is just a brief idea of what i will be doing. There's actually a lot more to it but if it will help to kick-start my CCS days..
|
This is a good approach. Simplify your first attempt as much as possible so that you don't bite off more than you can chew. If your initial approach is robust, it will be a lot easier to add functionality to it in small steps. However, it is important to be open to the possibility that your approach is flawed, which you might only discover after trying to make it work. At that time it may be best to take what you have learned and start over.
Robert Scott
Real-Time Specialties |
|
|
CCSNewbie
Joined: 15 May 2008 Posts: 12
|
|
Posted: Thu May 15, 2008 1:44 pm |
|
|
Yup, i've gotta agree with you that a single pedestrian might cause the sensor to bounce on/off a hundred times.
What if there's a certain small area that the pedestrian is supposed to stand(to activate the sensor)?
And, instead of calculating the amount of pedestrians, i will calculate the amount of cars(only cars for now, to simplify things)
I was thinking of using a single PIC16F877A just for the sensors. The actuators(lights) will be on another 877 connected as slave. So each time an interrupt happens, the master sends a couple bits of data to the slave to be executed and the process can continue as usual.
But it is necessary so that there is a delay between each interrupts so that the traffic does not get congested up due to pedestrians activating the PEDSENS(PIN_A2)
Are there any reliable sources where i can obtain sample codes for the Big Polling Loops?
Thanks in advance.
Any other suggestions/advices are welcomed. Seriously, please, do comment as i'm still new and criticisms can only do me good. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu May 15, 2008 2:00 pm |
|
|
If you have several different processes that must be performed or
supervised at different rates, and that must appear to be occurring
simultaneously, then consider a multi-tasking approach to the program
design:
http://www.ccsinfo.com/forum/viewtopic.php?t=17189 |
|
|
CCSNewbie
Joined: 15 May 2008 Posts: 12
|
|
Posted: Fri May 16, 2008 1:59 am |
|
|
PCM Programmer, according to the codes in the link you posted earlier, is it possible to detect how many times the interrupt has happened?
I want to count until the 1000th interrupt. As long as PIN_A0 is high, it will start counting from 0-1000th. IF anytime during the countdown PIN_A0 turns to low, the countdown stops and the counter is reset to 0.
Is it possible? |
|
|
RLScott
Joined: 10 Jul 2007 Posts: 465
|
|
Posted: Fri May 16, 2008 5:06 am |
|
|
CCSNewbie wrote: | PCM Programmer, according to the codes in the link you posted earlier, is it possible to detect how many times the interrupt has happened?
|
Yes, simply increment a variable every time you service an interrupt.
Quote: |
I want to count until the 1000th interrupt. As long as PIN_A0 is high, it will start counting from 0-1000th. IF anytime during the countdown PIN_A0 turns to low, the countdown stops and the counter is reset to 0.
Is it possible? |
Yes, this is a typical debouncing strategy.
Robert Scott
Real-Time Specialties |
|
|
CCSNewbie
Joined: 15 May 2008 Posts: 12
|
here goes nothing |
Posted: Fri May 16, 2008 10:39 am |
|
|
Ok guys, here's something that i came up with (using PCM Programmer's earlier program codes)
I still couldnt get the code to work as when i simulate it using Proteus Isis, LEDs connected to B0,B1,B2 and B7 lights up as soon as simulation is started.
(the way i wanted it was B0-B7 will light up after 1000 cycles of interrupt(10 seconds) in which input at PIN_A0 is HIGH)
Code: |
//----------------------------------------------------------------------
// DEFINES
//
// With a 4 MHz oscillator, a RTCC pre-scaler of 256, and a RTCC
// preload of 39, we get an rtcc interrupt rate of 100.16 Hz (Approx.
// every 10 ms).
// This will be our "tick" clock that we use for various event timers.
#define RTCC_PRELOAD (256 - 39)
// Multiply the following values x 10 ms to get the delay times,
// since each timer tick is 10 ms.
#define PED_SENS_TICKS 10 // 10 ms
#define CAR_SENS_TICKS 10 // 10 ms
#include <16F877A.h>
// GLOBALS
char ped_sens_timer;
char car_sens_timer;
char ped_sens_status;
int ped_sens_det;
void ped_sens(void);
void car_sens(void);
void ped_sens_check(void);
main()
{
set_tris_b(0b00000000);/*configure pins of PORTb as output*/
set_tris_a(0b00000011);/*configure A0 and A1 as input*/
ped_sens_status = (input(PIN_A0)); // Initialize pedestrian sensor input
// Initialize the software timers for each task.
// These initial values could even be different from
// the "normal" value, if you wanted the initial delay
// to be different than the normal task execution rate.
ped_sens_timer = PED_SENS_TICKS;
car_sens_timer = CAR_SENS_TICKS;
// Setup the RTCC.
setup_counters(RTCC_INTERNAL, RTCC_DIV_256);
set_rtcc(RTCC_PRELOAD);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
// This is the main loop used for multitasking purpose.
while(1)
{
ped_sens();
car_sens();
ped_sens_check();
}
}
//==============================
// If a pedestrian is detected for a period of longer than 10seconds at PIN_A0,
// the counter will keep on counting until a period of 1000th interrupts.
// At 10ms each interrupt, 1000 interrupts is almost equivalent to 10seconds.
void ped_sens(void)
{
int new_status;
if(ped_sens_timer)
return;
else
ped_sens_timer = PED_SENS_TICKS;
new_status = input(PIN_A0); // Read the sensor at pin A0
// Have the switches changed ?
if(new_status = 0)
{
Ped_sens_det++;
}
else
{
Ped_sens_det = 0;
}
}
//-----------------------------------------------------------
// This part of the coding checks to see whether the 1000th interrupt had
// been achieved. If it is the 1000th interrupt then another process will be called.
void ped_sens_check(void)
{
if(ped_sens_det == 1000)
{
output_b(0b11111111);
ped_sens_det =0;
}
else
{
Return;
}
}
//--------------------------------------------------------
void car_sens(void)
{
if(car_sens_timer)
return;
else
car_sens_timer = CAR_SENS_TICKS;
// Car sensors
}
//--------------------------------------------------------
// The rtcc interrupt occurs when the rtcc rolls over from FF to 00.
// I have programmed it to interrupt at a 100 Hz rate.
//
// RTCC interrupt rate = Fosc / (4 * rtcc pre-scaler * rtcc pre-load)
//
// = 4 MHz / (4 * 256 * 39)
//
// = 100.16 Hz
//
// This gives us a timer tick approx. every 10 ms (9.98 ms actually).
#int_rtcc
void rtcc_isr(void)
{
// Reload the RTCC, so it will keep overflowing every 10 ms.
set_rtcc(RTCC_PRELOAD);
// Decrement any timers that are running.
if(ped_sens_timer)
ped_sens_timer--;
if(car_sens_timer)
car_sens_timer--;
} |
|
|
|
CCSNewbie
Joined: 15 May 2008 Posts: 12
|
|
Posted: Fri May 16, 2008 10:49 pm |
|
|
Hey there Mr PCM Programmer.
Based on your code posted at the following link,
http://www.ccsinfo.com/forum/viewtopic.php?t=17189
we will never get the ELSE statement, wouldnt we?
Quote: | if(gc_buttons_timer)
return;
else
gc_buttons_timer = BUTTONS_TIMER_TICKS; |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri May 16, 2008 11:10 pm |
|
|
Yes, you will. Those variables are decremented in the timer tick isr.
When it counts down to 0 then you will execute the 'else' statement. |
|
|
CCSNewbie
Joined: 15 May 2008 Posts: 12
|
It works, but |
Posted: Sat May 17, 2008 5:20 am |
|
|
So far i have been able to turn make the LEDs blink after a certain period of time.
But new problems has cropped up.
1) Instead of 1000th interrupt (10 seconds), the LEDs lights up at 5seconds after i start the simulation. Are there any wrong values that i've inserted which causes this?
Quote: | void ped_sens_check(void)
{
if(ped_sens_det == 1000)
{
output_b(0b11111111);
ped_sens_det =0;
}
else |
2) In 'void ped_sens(void)' , Turning PIN_A0 to '0' is supposed to bring the code to the ELSE part, resetting the interrupt count to 0 and entirely stopping the process that makes the LED light up (unless PIN_A0 is high for another 10 seconds)
But apparently it's not working.
My LEDs at the outputs are still lighting up even though i switched off the input at PIN_A0.
I know i am doing a lot of things wrong? So please do let me know so i can correct them one at a time.
Much appreciation. CHeers
edit: my PIC is connected to an 8MHz crystal and the internal clock is set to 2MHz
Quote: | //----------------------------------------------------------------------
// DEFINES
//
// With a 4 MHz oscillator, a RTCC pre-scaler of 256, and a RTCC
// preload of 39, we get an rtcc interrupt rate of 100.16 Hz (Approx.
// every 10 ms).
// This will be our "tick" clock that we use for various event timers.
#define RTCC_PRELOAD (256 - 39)
// Multiply the following values x 10 ms to get the delay times,
// since each timer tick is 10 ms.
#define PED_SENS_TICKS 1 // 10 ms
#define CAR_SENS_TICKS 1 // 10 ms
#include <16F877A.h>
// GLOBALS
char ped_sens_timer;
char car_sens_timer;
char ped_sens_status;
int ped_sens_det;
void ped_sens(void);
void car_sens(void);
void ped_sens_check(void);
int new_status;
main()
{
set_tris_b(0b00000000);/*configure pins of PORTb as output*/
set_tris_a(0b00000001);/*configure A0 and A1 as input*/
output_a(0b000000000);
// Initialize the software timers for each task.
// These initial values could even be different from
// the "normal" value, if you wanted the initial delay
// to be different than the normal task execution rate.
ped_sens_timer = PED_SENS_TICKS;
car_sens_timer = CAR_SENS_TICKS;
// Setup the RTCC.
setup_counters(RTCC_INTERNAL, RTCC_DIV_256);
set_rtcc(RTCC_PRELOAD);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
// This is the main loop. You put your "tasks" here.
while(1)
{
ped_sens();
ped_sens_check();
}
}
//==============================
// If a pedestrian is detected for a period of longer than 10seconds at PIN_A0,
// the counter will keep on counting until a period of 1000th interrupts.
// At 10ms each interrupt, 1000 interrupts is almost equivalent to 10seconds.
void ped_sens(void)
{
if(ped_sens_timer)
return;
else
ped_sens_timer = PED_SENS_TICKS;
ped_sens_status = (input(PIN_A0)); // Initialize the button status
new_status = input(PIN_A0); // Read the sensor at pin A0
// Have the switches changed ?
if(new_status == 1)
{
Ped_sens_det++;
}
else if(new_status ==0)
{
Ped_sens_det = 0;
}
else
{
Ped_sens_det = 0;
}
}
//-----------------------------------------------------------
// This part of the coding checks to see whether the 1000th interrupt had
// been achieved. If it is the 1000th interrupt then another process will be called.
void ped_sens_check(void)
{
if(ped_sens_det == 1000)
{
output_b(0b11111111);
ped_sens_det =0;
}
else
Return;
}
//--------------------------------------------------------
// The rtcc interrupt occurs when the rtcc rolls over from FF to 00.
// I have programmed it to interrupt at a 100 Hz rate.
//
// RTCC interrupt rate = Fosc / (4 * rtcc pre-scaler * rtcc pre-load)
//
// = 4 MHz / (4 * 256 * 39)
//
// = 100.16 Hz
//
// This gives us a timer tick approx. every 10 ms (9.98 ms actually).
#int_rtcc
void rtcc_isr(void)
{
// Reload the RTCC, so it will keep overflowing every 10 ms.
set_rtcc(RTCC_PRELOAD);
// Decrement any timers that are running.
if(ped_sens_timer)
ped_sens_timer--;
if(car_sens_timer)
car_sens_timer--;
}
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat May 17, 2008 12:51 pm |
|
|
Check your variable declarations. Look in this section of the CCS manual.
This is on page 37 (page 49 in the Acrobat reader).
http://www.ccsinfo.com/downloads/CReferenceManual.pdf
Quote: |
DATA DEFINITIONS
Basic and Special types |
Ask yourself these questions:
You have several variables that are declared as a 'char'.
What is the largest number that can be held in a 'char' ?
Are you comparing a char variable to a number larger than a 'char' can hold ?
What size should you declare the variable as, so that it can be compared
to a number such as 1000 ?
You don't have to post the answers. Just look your program and fix the problems. |
|
|
CCSNewbie
Joined: 15 May 2008 Posts: 12
|
|
Posted: Sun May 18, 2008 2:00 am |
|
|
Thx PCM P, Int16 works :D
But i have a question.
Does the number of tasks in the main loop affect the timing of my interrupts?
Because according to my code, 1000th interrupt should be 10 seconds(1000x10ms).
But during simulation, the the 1000th interrupt is 20 seconds.
Does it mean that when i have 4 tasks in the main loop, my 1000th interrupt is 40 seconds?
Thx for ur time
Main Loop wrote: | // This is the main loop. You put your "tasks" here.
while(1)
{
ped_sens();
ped_sens_check();
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun May 18, 2008 6:41 am |
|
|
No. If the tasks are kept short, then adding tasks won't affect the
basic timing. What is your simulator ?
Also, I notice your code has no #fuses or #use delay statement. |
|
|
CCSNewbie
Joined: 15 May 2008 Posts: 12
|
|
Posted: Sun May 18, 2008 2:54 pm |
|
|
Right now i am using Proteus Isis 7 for the simulation task.
I just did a read through of the reference files for #fuses and #use delay statements.
Lets say if i have a crystal oscillator with a frequency of 8MHz connected
to the CLKIN and CLKOUT of my PIC16F877A does it mean my #fuses has got to be something like "#fuses XT,-insert other modes-" ?
I am not sure if my codes have the need for all the other options like BROWNOUT,WDT,PROTECT etc.
Concerning the delay, same like above, if i never utilize any kind of delays in my code i do not think i need to add the #use delay. Please correct me if i got this wrong.
Below i have included my Current codes.
It takes 5 seconds of continuous input on either PIN_A1/PIN_A0 or BOTH to activate the outputs at PORT B. (250th interrupt = 5 seconds, 500th interrupt = 10 seconds and so on)
If anytime during the 5 seconds i stop the input for either PIN_A1 or PIN_A0 then the counter is reset (another 5 seconds of continuous input is needed).
Or maybe i have misunderstood a little bit on how the codes work?
Maybe it's meant to be this way.
**Awaiting enlightenment**
Code: |
//----------------------------------------------------------------------
// DEFINES
//
// With a 4 MHz oscillator, a RTCC pre-scaler of 256, and a RTCC
// preload of 39, we get an rtcc interrupt rate of 100.16 Hz (Approx.
// every 10 ms).
// This will be our "tick" clock that we use for various event timers.
#define RTCC_PRELOAD (256 - 39)
// Multiply the following values x 10 ms to get the delay times,
// since each timer tick is 10 ms.
#define PED_SENS_TICKS 1 // 10 ms
#define CAR_SENS_TICKS 1 // 10 ms
#include <16F877A.h>
// GLOBALS
int ped_sens_timer; // Defining
int ped_sens_timer2; // the
int car_sens_timer; // variables
int ped_sens_status; //
int ped_sens_status2; //
int16 ped_sens_det; //
int16 ped_sens_det2; //
void ped_sens(void); // Declaring
void ped_sens2(void); // the
void car_sens(void); // main
void ped_sens_check(void); // functions
void ped_sens_check2(void); //
main()
{
set_tris_b(0b00000000);/*configure pins of PORTb as output*/
set_tris_a(0b00000011);/*configure A0 and A1 as input*/
output_b(0b00000000);
output_a(0b00000000);
// Initializing the software timers for each task
ped_sens_timer = PED_SENS_TICKS;
ped_sens_timer2 = PED_SENS_TICKS;
car_sens_timer = CAR_SENS_TICKS;
// Setup the RTCC interrupts.
setup_counters(RTCC_INTERNAL, RTCC_DIV_256);
set_rtcc(RTCC_PRELOAD);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
// This is the main loop for the tasks.
while(1)
{
ped_sens();
ped_sens2();
car_sens();
ped_sens_check();
ped_sens_check2();
}
}
//==============================
// PEDESTRIAN SENSOR 1
// If a pedestrian is detected for a period of longer than 10 seconds at PIN_A0,
// the counter will keep on counting until a period of 1000th interrupts.
// At 10ms each interrupt, 1000 interrupts is almost equivalent to 10seconds.
void ped_sens(void)
{
if(ped_sens_timer)
{
return;
}
else
{
ped_sens_timer = PED_SENS_TICKS;
}
ped_sens_status = (input(PIN_A0)); // Initialize the button status
// Have the switches changed ?
if(ped_sens_status == 0) //If pedestrian is not detected ,reset
{
Ped_sens_det = 0;
}
else if(ped_sens_status == 1) // If pedestrian is detected, counter +
{
Ped_sens_det++;
output_bit( PIN_A0, 0);
}
}
//-----------------------------------------------------------
// This part of the coding checks to see whether the 1000th interrupt had
// been achieved. If it is the 1000th interrupt then another process will be
// called.
void ped_sens_check(void)
{
if(ped_sens_det == 250)
{
output_b(0b11111111);
ped_sens_det =0;
}
else
Return;
}
//------------------------------------------------------------------------------
// PEDESTRIAN SENSOR 2
// This is exactly same like the part on top but it checks for the second
// pedestrian sensor at PIN_A1.
void ped_sens2(void)
{
if(ped_sens_timer2)
{
return;
}
else
{
ped_sens_timer2 = PED_SENS_TICKS;
}
ped_sens_status2 = (input(PIN_A1)); // Initialize the button status
// Have the switches changed ?
if(ped_sens_status2 == 0)
{
Ped_sens_det2 = 0;
}
else if(ped_sens_status2 == 1)
{
Ped_sens_det2++;
output_bit( PIN_A1, 0);
}
}
//-----------------------------------------------------------
// This part of the coding checks to see whether the 1000th interrupt had
// been achieved for the SECOND SENSOR.
void ped_sens_check2(void)
{
if(ped_sens_det2 == 250)
{
output_b(0b11111111);
ped_sens_det2 =0;
}
else
Return;
}
//--------------------------------------------------------
void car_sens(void)
{
if(car_sens_timer)
return;
else
car_sens_timer = CAR_SENS_TICKS;
// Car sensors
}
//--------------------------------------------------------
// The rtcc interrupt occurs when the rtcc rolls over from FF to 00.
// I have programmed it to interrupt at a 100 Hz rate.
//
// RTCC interrupt rate = Fosc / (4 * rtcc pre-scaler * rtcc pre-load)
//
// = 4 MHz / (4 * 256 * 39)
//
// = 100.16 Hz
//
// This gives us a timer tick approx. every 10 ms (9.98 ms actually).
#int_rtcc
void rtcc_isr(void)
{
// Reload the RTCC, so it will keep overflowing every 10 ms.
set_rtcc(RTCC_PRELOAD);
// Decrement any timers that are running.
if(ped_sens_timer)
ped_sens_timer--;
if(ped_sens_timer2)
ped_sens_timer2--;
if(car_sens_timer)
car_sens_timer--;
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun May 18, 2008 3:03 pm |
|
|
How does Proteus know what your oscillator speed is ? I don't have
Proteus so I can't trouble-shoot any problems or configuration issues
with it. I can't do much more on this. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|