View previous topic :: View next topic |
Author |
Message |
ccslearner
Joined: 12 Jan 2013 Posts: 10
|
Timer interrupt on pic16f877a |
Posted: Sun Jan 20, 2013 12:42 am |
|
|
Can anyone help me solve my problem ? I am using ccs compiler and PIC 16F877A. The assignment that was given to me is, write a program to glow LEDs in the following order, simultaneously:
LED1 - ON EVERY 5 sec and OFF EVERY 5 sec
LED2 - ON EVERY 2 sec and OFF EVERY 2 sec
Important, it should happen simultaneously, using timer2 interrupt.
Here I post my code also.
Code: |
#include <timer1.h>
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
int1 two_sec_timer_flg = FALSE,five_sec_timer_flg =FALSE;
unsigned int16 two_sec_count= FALSE ,five_sec_count = FALSE;
#INT_TIMER2
void timer2_isr()
{
two_sec_count++;
five_sec_count++;
{
if(two_sec_count == 200)
{
two_sec_count = 0;
two_sec_timer_flg = TRUE;
}
if(five_sec_count==1000)
{
five_sec_count=0;
five_sec_timer_flg=TRUE;
}
}
}
void main ()
{
//setup_timer_2(T2_DIV_BY_4,78,16);//setup up timer2 to interrupt every 1ms
setup_timer_2(T2_DIV_BY_4,250,5); //setup up timer2 to interrupt every 1ms
//setup_timer_2 (mode, period, post scale)
//mode - T2_DISABLED, T2_DIV_BY_1, T2_DIV_BY_4, T2_DIV_BY_16
//period is a int 0-255 that determines when the clock value is reset,
//post scale is a number 1-16 that determines how many timer overflows before
//an interrupt: (1 means once, 2 means twice, and so on).
// calculating timer reload value to generate 1 msec interrupt
// T = 1/f
// T = 1/4MHZ = 1/4* 1000000
// But Microcontroller hardware will divide the clock by 4
// and if we chosen T2_DIV_BY_4 then again there will
// one more division happen by 4
// So T = 1/(4 * 1000000)/ 4 * 4 / T=4/4*1000000
// T = 4*4/4*1000000 = 0.000004 sec = 0.4 usec //4 usec
// ************************************************
// At 4mhz, the timer will increment every 0.4 us // 4 usec *// 0.000004 sec
// ************************************************
// ********************************************************
// if period is chosen 250 then timer wi
//ll overflow every *
// 4 * 250 = 25 usec // 1000 usec //1 msec *
// ********************************************************
// *******************************************************************
// And if we chosen post scalar as 5 then timer interrupt will occur *
// 25 usec * 5 = 125 usec // 5000 usec /// 5 msec
// *******************************************************************
enable_interrupts(INT_TIMER2); // enable timer2 interrupt
enable_interrupts(GLOBAL);
putc('Z');
//infine loop
while (1)
{
if( two_sec_timer_flg == TRUE)
{
printf("I am in 2 sec \n\r");
output_b (0x1);
delay_ms(2000);
output_b(0x00);
delay_ms (2000);
}
if( five_sec_timer_flg == TRUE)
{
printf ("I am in 5 sec \n\r" );
output_b (0x2);
delay_ms(5000);
output_b (0x00);
delay_ms (5000);
}
}
}
|
I was compiling this code but the output does not come simultaneously. Please cite me to what mistake I made and correct it please. Thanks. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Sun Jan 20, 2013 2:05 am |
|
|
If your interrupt is being called every mSec, then the interrupt code is being executed every mSec. You have two 16bit additions here and two 16bit tests. A total of about 16uSec of code. Then about another 30uSec to get into and out of the interrupt handler, so just under 50uSec/mSec of code. So delays in the main code would run slow by about 5%.
Then in your 2 second code, you sit for 4 seconds (actually more like 4.2 seconds because of the above), plus about 15mSec for the serial, before calling the 'five second' code which then takes about 11 seconds to run. By which time you will have missed both a 2 second timer, and a 10 second timer....
You need to use either interrupt timings, _or_ software timings.
So, something like:
Code: |
#include <timer1.h>
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
int1 two_sec_timer_flag = FALSE,five_sec_timer_flag = FALSE;
#INT_TIMER2
void timer2_isr(void) {
//Keep variables that are local _local_
static int8 tick=100;
static int8 two_sec=2;
static int8 five_sec=5;
if (--tick == 0) {
//Here once per second
tick=100;
if (--two_sec==0){
output_toggle(PIN_B0);
two_sec=2;
two_sec_timer_flag^=1;
}
if (--five_sec==0){
output_toggle(PIN_B1);
five_sec=5;
five_sec_timer_flag^=1;
}
}
}
void main (void) {
int1 last_2sec, last_5sec;
setup_timer_2(T2_DIV_BY_16,125,5); //setup up timer2 to interrupt every 10ms
//Don't do things faster than you have to
//remember the period counts from _0_ to the count, so you need period -1
//*************************
//100*per second. 4000000/100 = 40000
//40000/4=10000 - so total count wants to be 10000.
//16*125*5 = 10000
//So prescale /16, period 124, postscale 5
last_2sec=two_sec_timer_flag;
last_5sec=five_sec_timer_flag;
enable_interrupts(INT_TIMER2); // enable timer2 interrupt
enable_interrupts(GLOBAL);
putc('Z');
//infinite loop
while (TRUE) {
if(two_sec_timer_flag!=last_2sec) {
//here flag has _changed_
last_2sec=two_sec_timer_flag;
printf("I am in 2 sec \n\r");
}
if( five_sec_timer_flag!=last_5sec){
last_5sec=five_sec_timer_flag;
printf ("I am in 5 sec \n\r" );
}
}
}
|
Now notice that the only variables that are global, are the two flags. The local variables to the interrupt are static variables inside this routine. Reduces the risk of the wrong thing changing things.
Best Wishes |
|
|
ccslearner
Joined: 12 Jan 2013 Posts: 10
|
|
Posted: Sun Jan 20, 2013 8:35 am |
|
|
Thankyou so much mr Ttelmah actually i am in the beginning stage of ccs codes and also i understand again thank u u .. . , |
|
|
ccslearner
Joined: 12 Jan 2013 Posts: 10
|
|
Posted: Sun Jan 20, 2013 8:46 am |
|
|
pease cite me to my code what code i changed to get output? please sent me |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Sun Jan 20, 2013 9:05 am |
|
|
It already gives an output.
The 'output_toggle' lines in the interrupt, toggle the B0 (2second), and B1 (5 second) connections.
The only reason this wouldn't work, is if the lines are overloaded (what resistor value are you using to drive the LED's).
Best Wishes |
|
|
ccslearner
Joined: 12 Jan 2013 Posts: 10
|
|
Posted: Sun Jan 20, 2013 9:11 am |
|
|
Thank you for your valuable reply. Sorry to interrupt again, can you tell me any tutorial or books to learn embedded C for PIC mcu ? |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Sun Jan 20, 2013 10:29 am |
|
|
The CCS examples folder shows you how to drive many of the PIC peripehrals.
Try them out for starters.
Won't cost you much. Just need access to a few standard bits and pieces.
Mike |
|
|
ccslearner
Joined: 12 Jan 2013 Posts: 10
|
|
Posted: Sun Jan 20, 2013 12:33 pm |
|
|
thanks to all to reply i ask any link for read free like tutorials for PIC16F877A |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Sun Jan 20, 2013 4:25 pm |
|
|
ccslearner wrote: | thanks to all to reply i ask any link for read free like tutorials for PIC16F877A | To a large extent CCS insulates you from the differences between PICs.
You can find the specifics for your PIC in its data sheet.
(The data sheet tells you which peripherals are available)
The '877A is a mature product, there should be few (if any) compiler bugs.
You'll learn a lot by simply playing with (experimenting/modifying) the CCS examples.
Mike |
|
|
ccslearner
Joined: 12 Jan 2013 Posts: 10
|
|
Posted: Mon Jan 21, 2013 10:56 am |
|
|
Thanks mike actually i know already all peripherals are available in pic data sheet. As a beginner i am asking to best link for programming PIC16F877A in c because i am lacking in programming not hardware.
Anyway thanks
Noorul |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Mon Jan 21, 2013 11:10 am |
|
|
One of us is missing the point.
The CCS examples show you how to program almost any PIC to get its peripherals to do what you want.
The only reason for needing the data sheet is to discover what each pin does.
(For example the uart on an 18F1320 is on different pin names and numbers to your 16F877A, but the programming is similar in CCS.)
To a large extent it doesn't matter which PIC you're using.
Other compilers force you to know a lot more about the individual PIC you're using.
Mike |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Mon Jan 21, 2013 1:38 pm |
|
|
Interrupt density, that is - how many times /second - does the interrupt fire - is a very important aspect of program design.
My general rule of thumb is to make the timer #INT service be as infrequent as possible, given the required resolution of your MAIN(), timed activity. If i was doing your school work, i would opt to use a timer interrupt rollover of 250 msecs or there about.
Higher than required timer interrupt density degrades the performance of all aspects of your MAIN program and its called functions.
just my 2 cents |
|
|
ccslearner
Joined: 12 Jan 2013 Posts: 10
|
To modify my code |
Posted: Wed Jan 23, 2013 11:44 am |
|
|
Code: |
#include <timer1.h>
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
int1 two_sec_timer_flag = FALSE,five_sec_timer_flag =FALSE,ten_sec_timer_flag = FALSE ;
int16 two_sec_count,five_sec_count,ten_sec_count;
#INT_TIMER2
void timer2_isr()
{
two_sec_count++;
five_sec_count++;
ten_sec_count++;
{
if(two_sec_count == 400) // 400 * 5 msec = 2000 msec = 2 sec
{
two_sec_count = 0;
two_sec_timer_flag = TRUE;
}
if(five_sec_count==1000) /// 1000 * 5 msec = 5000 msec = 5 sec
{
five_sec_count=0;
five_sec_timer_flag=TRUE;
}
if(ten_sec_count == 2000) // 2000 * 5 =10000 msec = 10 sec
{
ten_sec_count = 0 ;
ten_sec_timer_flag = TRUE;
}
}
}
void main ()
{
int1 last_2sec,last_5sec,last_10sec;
//setup_timer_2(T2_DIV_BY_4,78,16);//setup up timer2 to interrupt every 1ms
setup_timer_2(T2_DIV_BY_4,255,5); //setup up timer2 to interrupt every 1ms
//setup_timer_2 (mode, period, post scale)
//mode - T2_DISABLED, T2_DIV_BY_1, T2_DIV_BY_4, T2_DIV_BY_16
//period is a int 0-255 that determines when the clock value is reset,
//post scale is a number 1-16 that determines how many timer overflows before
//an interrupt: (1 means once, 2 means twice, and so on).
// calculating timer reload value to generate 1 msec interrupt
// T = 1/f
// T = 1/4MHZ = 1/4* 1000000
// But Microcontroller hardware will divide the clock by 4
// and if we chosen T2_DIV_BY_4 then again there will
// one more division happen by 4
// So T = 1/(4 * 1000000)/ 4 * 4 / T=4/4*1000000
// T = 4*4/4*1000000 = 0.000004 sec = 0.4 usec //4 usec
// ************************************************
// At4mhz, the timer will increment every 0.4 us // 4 usec *// 0.000004 sec
// ************************************************
// ********************************************************
// if period is chosen 250 then timer wi
//ll overflow every *
// 4 * 250 = 25 usec // 1000 usec //1 msec *
// ********************************************************
// *******************************************************************
// And if we chosen post scalar as 5 then timer interrupt will occur *
// 25 usec * 5 = 125 usec // 5000 usec /// 5 msec
// *******************************************************************
last_2sec=FALSE;
last_5sec=FALSE;
last_10sec=FALSE;
enable_interrupts(INT_TIMER2); // enable timer2 interrupt
enable_interrupts(GLOBAL);
output_b(0x0); // off all theLEDS
putc('z');
//infine loop
while (1)
{
if( two_sec_timer_flag == TRUE)
{
two_sec_timer_flag = FALSE;
//printf("I am in 2 sec \n\r");
last_2sec = ~last_2sec;
if ( last_2sec == TRUE)
{
output_b( (input_b() | 0x01)); // ON LED 1 alone
}
else
{
output_b( (input_b() & 0xFE)); // OFF LED 1 alone
}
}
if( five_sec_timer_flag == TRUE )
{
five_sec_timer_flag = FALSE;
// printf ("I am in 5 sec \n\r" );
last_5sec = ~last_5sec;
if ( last_5sec == TRUE)
{
output_b( (input_b() | 0x02)); // ON LED 2 alone
}
else
{
output_b( (input_b() & 0xFD)); // OFF LED 2 alone
}
}
if( ten_sec_timer_flag == TRUE)
{
ten_sec_timer_flag = FALSE;
//printf("i am in 10 sec \n\r");
last_10sec = ~last_10sec;
if(last_10sec==TRUE)
{
output_b( (input_b() | 0x04) ); // ON LED3 alone
}
else
{
output_b( (input_b() & 0xFB)); // OFF LED 3 alone
}
} // end of while
} // end of main
}
|
Hai to all pofessional experts this is my code to blink 3 led simultaneously:
led 1 2_sec ON and OFF
led 2 5_sec ON and OFF
LED 3 10_sec ON and OFF
this are clear to get my output. My question is how to change these code to get output like given below:
Write a program to turn Led 1 ON for 3 sec and OFF for 5 sec? And repeat the same sequence.
THANKS
Noorul(BEGINNER) |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Wed Jan 23, 2013 2:32 pm |
|
|
You've (or your tutor's) changed the rules.
So, you either extend the present scheme or change to something more general purpose.
Mike |
|
|
|