|
|
View previous topic :: View next topic |
Author |
Message |
TaiChipY
Joined: 11 Mar 2005 Posts: 21
|
Timer 1 , 2 ---> 18F452 |
Posted: Tue Mar 15, 2005 10:22 am |
|
|
I saw the timers topic but this has solved party my problem...
I need just some explanation on part where im using two timers...
First timer is used like countdown and its working on 16F877.
Since i added the second timer and since the speed / MCU has been changed,i have some problems with displaying the value ( time ) of the first counter. Counted time value is wrong and i have had small problems with second timer ( fixed ), becuse of the first counter...
Im using 8MHZ clock on 18F452 and both internal timers.
This is the code part:
Code: | #include <18F452.h>
#use delay(clock=8000000)
#fuses HS, NOWDT, PUT, NOLVP
#include "PICDEM_LCD.C"
#include "flasher.c"
#define COUNTDOWN sati
int sekunde=0,sati=5,dani=5;
#int_TIMER1
TIMER1_isr()
{
set_timer1(0xF000);
sekunde++;
if (sekunde==3600)
{
sekunde=0;
sati--;
}
if (sati==24)
{
sati=0;
dani--;
}
}
#int_timer2
void timer2_isr(void)
{
if (Miliseconds < 0xFF)
Miliseconds++;
}
voin main()
{
lcd_init();
setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
setup_timer_2(T2_DIV_BY_4,(8000000/80000),5);
enable_interrupts(INT_TIMER1);
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
printf(lcd_putc,"Time: %3d", sati) // just test for hours
} |
Can someone explain me what is the "normal way" to do the math for such situation and how does the timer1 and timer2 "interact" and what would happen if i would add another timer ( some other chip )..
Thanx |
|
|
Ttelmah Guest
|
|
Posted: Tue Mar 15, 2005 4:23 pm |
|
|
Unfortunately, the 'key thing', is to forget setting timer1 to a value!...
The problem is that timer1, is counting in instruction times. When your code arrives in the interrupt handler, there will typically have been at least 25 instruction times from the moment the interrupt occurred, so setting the timer to a value, will be in error by this interval. Worse, the interval will change. With two interrupts present (doesn't have to be a timer, could be a serial interrupt, or any other source), if the timer interrupt occurs once the code has already entered the other interrupt handler, the whole of this handler will have to execute, then the code to restore the registers, then the return from interrupt, followed by the next interrupt call, and it's overhead to save the registers. Even with a quick interrupt handler, the error will jump to perhaps 75 to 100 instruction times in the worst case...
Do a search on this forum, for posts on handling a clock interrupt, and particularly a RTC. There has been a version published in the past, which shows a very efficient way (using an integer addition), to generate an accurate timing for a system 'tick', without tweaking the timer counter value. Alternatively, change timers, and use the hardware ability to reset the timer, available from the CTC. Realise also, that the RTCC, with a /16 prescaler, will give the same rate as timer1, with the tweak you show.
You can reduce the error, by adding an offset to the timer value (rather than an absolute value), but this is best applied when dealing with a timer 'ticking' at a much slower rate, than the instruction clock speed.
Best Wishes |
|
|
TaiChipY
Joined: 11 Mar 2005 Posts: 21
|
|
Posted: Wed Mar 16, 2005 2:22 am |
|
|
Unfortunately, the 'key thing', is to forget setting timer1 to a value!...
**
aaaaaaaaaaaaaaaaaaaaaaaaa, sorry my mistake :--)
Thanx anyway ! |
|
|
TaiChipY
Joined: 11 Mar 2005 Posts: 21
|
|
Posted: Mon Mar 28, 2005 12:53 pm |
|
|
I have tested three timers 0,1,2.
and regarding to last post i made this changes.
Instead Timer1 am using ccp1.
Timer0 is used for 10 seconds timeout
Timer1 for countdown --> ccp1
Timer2 for button clicks interrupts
Q.
Can i use ccp1 for displaying the countdown (so i can work normaly with no conflicts with other timers) ? Any idea would be good....
Just an example:
This are settings for 16F917 chip:
Code: | ---------------------------
#byte CCP1CON = 0x17 // compare mode
#byte CCPR1H = 0x16
#byte CCPR1L = 0x15 // compare value 4095
#byte PIE1 = 0x8C
#byte PIR1 = 0x0C
#bit CCP1IF=PIR1.2
#bit CCP1IE=PIE1.2 // activate
---------------
....
#int_Timer0 // -- timer0
clock()
{
milisekunde_TO++;
if(milisekunde_TO>999)
{
miliSekunde_TO=0;
sekunde_TO++;
brojiSekunde=1;
}
}
--------------
....
#INT_CCP1 //--- timer 1
void CCP1_isr()
{
//restart_wdt();
sekunde++;
if (sekunde==3600)
{
sekunde=0;
minute--;
sati--;
}
if (sati==24)
{
sati=0;
dani--;
}
}
------------------
....
#int_timer2 // -- timer 2
void timer2_isr(void)
{
if (Miliseconds < 0xFF)
Miliseconds++;
}
------
void main (void)
{
CCP1CON = 0x0B;
CCPR1H = 0x0F;
CCPR1L = 0xFF;
setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
setup_ccp1(CCP_COMPARE_INT); ---> ???
setup_timer_2(T2_DIV_BY_4,(8000000/80000),5);
enable_interrupts(INT_Timer0);
enable_interrupts(INT_CCP1);
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
lcd_init();
/*
void reset_timer1(void)
{
zadnja_minuta = minute;
minute=60;
}
*/
while(TRUE)
{
if(minute != 0)
{
lcd_gotoxy(1,1);
printf(lcd_putc,"\f%02u:%02u",sati,minute); // Hours, min.
delay_ms(250);
}
}
} |
|
|
|
TaiChipY
Joined: 11 Mar 2005 Posts: 21
|
|
Posted: Wed Mar 30, 2005 4:51 am |
|
|
Can someone take a look and tell my if this is possible to make this on the described way ( with ccp )..
Thank you in advance. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Mar 30, 2005 4:47 pm |
|
|
I'm not really sure what you want to do. Do you want to use the CCP1 to generate an interrupt every second? If yes, then how do you want to feed the CCP1 counter? With an external clock pulse or from one of the internal ltimers? If you are thinking about using one of the internal timers like in your first example, then using the CCP1 is overkill and a waste of resources.
Like Ttelmah already told you, search this forum for the keyword 'RTC' and you will find some very nice examples (I know because I reposted a nice example from Neutone a few times and am too lazy to do it again now. Sorry).
Please post a complete program, several variable declarations are missing now, for example sekunde.
Code: | if (sekunde==3600)
{
sekunde=0;
minute--;
sati--;
}
if (sati==24)
{
sati=0;
dani--;
}
|
1) In your first example sekunde was declared as int, which in CCS equals int8. Comparing with 3600 will fail for an int8 which has a maximum of 255.
2) In my country we have 60 seconds in a minute, not 3600.
3) Not sure what you want to do, but in your first example you initialised sati to 5. My guess is you mean sati++ instead of sati-- ??
Do you really need two seperate timers both counting in milliseconds? You will save a lot of overhead by joining those two timers, and it frees a hardware timer for other purposes (or disable it to lower consumption). |
|
|
TaiChipY
Joined: 11 Mar 2005 Posts: 21
|
|
Posted: Thu Mar 31, 2005 5:47 am |
|
|
Code: | #byte CCP1CON = 0x17
#byte CCPR1H = 0x16
#byte CCPR1L = 0x15
#byte PIE1 = 0x8C
#byte PIR1 = 0x0C
#bit CCP1IF=PIR1.2
#bit CCP1IE=PIE1.2
//-------------------------------
int16 sekunde_TO, miliSekunde_TO;
int8 timeout_10;
int1 brojiSekunde=0, brojiDesetSekundi=0, timeout_clock_aktivirani=0;
#int_Timer0 // -- timer0
clock()
{
milisekunde_TO++;
if(milisekunde_TO>999)
{
miliSekunde_TO=0;
sekunde_TO++;
brojiSekunde=1;
}
}
//--------------------------------------------------------
int8 sekunde=0, days=2
unsigned sati=24, last_min=0;
#INT_CCP1 //CCP1 //--- timer 1
void CCP1_isr()
{
//restart_wdt();
sekunde++;
if (sekunde==3600)
{
sekunde=0;
sati--;
}
if (sati==24)
{
sati=0;
days--;
}
}
//------------------------------------------------------
#int_timer2 // -- timer 2
void timer2_isr(void)
{
if (Miliseconds < 0xFF)
Miliseconds++;
}
//*********************************************************
void main (void)
{
CCP1CON = 0x0B;
CCPR1H = 0x0F;
CCPR1L = 0xFF;
Miliseconds = 0; // int8
setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
setup_ccp1(CCP_COMPARE_INT); ---> ???
setup_timer_2(T2_DIV_BY_4,(8000000/80000),5);
enable_interrupts(INT_Timer0);
enable_interrupts(INT_CCP1);
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
lcd_init();
//---------------- test --------------------------
while(TRUE)
{
if(sati != 0)
{
lcd_gotoxy(1,1);
printf(lcd_putc,"\f%02u:%02u",sati,minute); // Hours, min.
delay_ms(250);
}
}
} |
Please forget the first example becuse since then most of the hardware parts have been changed. I have look for all of RTC but none of them explain the use of multiple timers.
Explanations:
Timer0 is cca 10 seconds timeout
Timer1 is countdown for days and hours ( in this case 2 days and 24 hours )
Timer2 is counter/timer for clicks (one, double clicks)
Timer1 must be active all the time (and during sleep).
From Timer1 i want to take cca 2 minutes to shutdown the lcd ( it's not in the code). So, lcd will be shutdowned each 2 minutes and waked up again on button click. The sleep mode will be activated in the same way (after 2 min). Timeout 10 sec will be activated just two times.
That's why i think that ccp was good approach....
What i don't understand
If i don't use ccp:
- set timer0, timer1, timer2 ---> i get problems with calculations and display
*so setting the timer to a value, will be in error by this interval*
I read ansewer from Ttelmah few times and i understand why my last approach was wrong,and thats why i have tried to solve the situation thru CCP ( i could not find the example ).
If i use CCP:
If you are thinking about using one of the internal timers...
I have to use internal timer1.
Do you really need two separate timers both counting in milliseconds?
I suppose i can join them together but then again, am not sure will this work
(regarding the tasks of timer0 and timer2).
Alternatively, change timers, and use the hardware ability to reset the timer..
I could do that, but then again i have to use timer1 for countdown, becuse timer1 has to be coundowning all the time and he is the only active timer during sleep...
In my country we have 60 seconds in a minute, not 3600.I can't stop laughting :-)))) For such comments i love this forum :--)).
That was lefted from the old code ( where sekunde == 60 ) :--)).
Sorry and please keep this attitude becuse of such comments my working day is fully refreshed :-)
The Green_Kid_From_Mars |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Thu Mar 31, 2005 8:15 am |
|
|
Your timer2 looks like my handy work. There is really no need to have all the other timers since you have such a small "system tick". You could just count to 1000 in the timer2 to get seconds or even do it in the main loop. You can either add the Miliseconds to another variable and anytime it is over 1000 increment the seconds and subtract 1000 from the counter or just have a loop while (Miliseconds) and increment the count by one. |
|
|
TaiChipY
Joined: 11 Mar 2005 Posts: 21
|
|
Posted: Tue Apr 05, 2005 9:51 am |
|
|
Hi Mark!
Im realy sorry for so much time taken for replay!
Im making some experiment with segmented LCD.
Your timer2 looks like my handy work
Yep this is your part of code.
Ok. I have done like you suggested and its OK accept timing part ).
Q1. Timer1:
clock = 8MHZ
8MHZ / 4 = 0.5 uS
1 seconds = 2000000
2000000 / 256 = 7812,5
If my counting is correct this should count (correctly) seconds and substract hours. But :--) how to define this in the timer1 ( becuse of the precision ).
Code: | //set_timer1(); -->
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1); |
Q2.
After 2 minutes i switch in the sleep modus.
What happens with counter on new wakeup?
I know that timer1 is counting thru sleep time, but now i have 10 seconds and 2 minutes timeout which should be reseted on wakeup ( and on the same timer )... So, i can't reset the whole timer,the only possible
way is to set some value (miliSekunde_TO = 0) after some button click for recounting. Is this good approach or do you have better one?
Q3. This could be a bit silly question... but anyway :-)
After 10 seconds timeout i can't set the value for lcd wakeup.
Im using your state mascine example with case (single_click_event)
Basicly, what happens: Since this is switch case option the function
(timeout)is called once per button click.
Welcome
> 10 sec -- shutdown lcd
first time button press
Welcome
> 10 sec -- shutdown lcd
and whole stuff again until OTHER button is pressed und until value im memory is = 1. So basicly, Wellcome will be displayed on first boot, and so long until B0 is pressed.
I have put the function in the case of the single_click_event. I will rewrite and send you example but if you have idea how to solve this on other way just write down.
Thanx Mark |
|
|
TaiChipY
Joined: 11 Mar 2005 Posts: 21
|
|
Posted: Wed Apr 06, 2005 3:41 am |
|
|
... i forgot to ask just one more thing.
Becuse the switch part is made thru timer2, and wenn chip goes to sleep,
timer 2 is inactive, can i wakeup the chip thru button click ??. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Apr 06, 2005 8:13 am |
|
|
Do you really need a millisecond counter? Counting milliseconds when you are only using timeouts in multiples of whole seconds gives a lot of overhead.
Timer1 is one of the few devices still operating in sleep mode, but ONLY when the clock pulse is provided by an external clock or crystal connected to timer1. Is this the way you have setup your hardware? Your call to setup_timer_1 is using the internal timer.............
I have the feeling that you are creating a way more difficult design than nescessary. I have no clue as to what your system is supposed to do , so I might be wrong. It might help if you tell us what your application is supposed to do.
When your application requires an accurate clock but also low power consumption then you have the following options:
1) Your current 18F452 with a 32768 Hz crystal connected to timer1
2) Using the watchdog for timekeeping during sleep (less accurate).
3) Use an external RTC like the DS1305 (SPI bus)
4) Choose another processor from the Microchip nanowatt line with inbuilt RTC.
Have you realized the 18F452 is not recommended for new designs and more expensive than most newer chips with more capabilities? |
|
|
TaiChipY
Joined: 11 Mar 2005 Posts: 21
|
|
Posted: Wed Apr 06, 2005 10:31 am |
|
|
Im using 16F917 and i want to make low power application.
This are the infos from 16F917 Timer1.
16-bit timer/counter (TMR1H:TMR1L)
Readable and writable
Internal or external clock selection
Synchronous or asynchronous operation
Interrupt-on-overflow from FFFFh to 0000h
Wake-up upon overflow (Asynchronous mode)
In Timer mode, Timer1 is incremented on every
instruction cycle. In Counter mode, Timer1 is incremented
on the rising edge of the external clock input T1CKI.
Timer1 can use the LP oscillator as a clock source.
-----------------------------------------------
To minimize the multiplexing of peripherals on the I/O
ports, the dedicated TMR1 oscillator, which is normally
used for TMR1 real time clock applications, is eliminated.
Instead, the TMR1 module can enable the LP oscillator.
-----------------------------------------------
Sleep mode does not shut off the LP oscillator
operation (i.e., if the INTOSC oscillator runs the
microcontroller, and T1OSCEN = 1 (TMR1 is
running from the LP oscillator), then the LP
oscillator will continue to run during Sleep mode.
------------------------------------------------
When INTOSC without CLKO oscillator is
selected and T1OSCEN = 1, the LP
oscillator will run continuously independent
of the TMR1ON bit.
-------------------------------------------------------------
I have no external clock becuse i thought that i can access to internal clock as it was described before
|
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Sun Apr 10, 2005 7:40 am |
|
|
It looks like a nice processor with Nanowatt tecnologie and LCD-driver logic built in. The Timer1 clock driver in this chip is different from what I've seen in other chips, and yes it seems perfect for running in low-power applications. Use a 32768 external crystal in LP-mode during sleep and for high performance switch to the internal clock oscillator.
I guess you can use this processor but I only have hands on experience with the PIC18F458 and this processor is very different, so don't take my word for it.
Just two final remarks:
1) In the Microchip product selector list this particular chip is listed as a 'future product'. PIC16F913 and PIC16F914 are in production.
2) 14336 bytes of program memory equals 8192 instructions. This is not much and currently no higher capacity models are available, be aware of this risk. |
|
|
TaiChipY
Joined: 11 Mar 2005 Posts: 21
|
|
Posted: Thu Apr 14, 2005 2:09 pm |
|
|
Well i thought that i solved this one out, but :--).
My timer1 is too fast (cca 1 min. == 122 sec.)
and my Timer2 can't get the right count (not near).
MCU is running on 8MHz and this is what i have tryed:
I have defined new prescaler (in devices dir )... no effect.
I have set the calculated value in the set_timer1... no good (infact, no changes)
I thought to access directly thru registers -- didn't try
Code: | -----------------------------------------------------
clock = 8MHZ
8MHZ / 4 = 0.5 uS
1 seconds = 2000000
2000000 / 256 = 7812,5
If my counting is correct this should count (correctly) seconds and substract hours. This is the formula but there is something wrong.
#INT_TIMER1
void timer1_isr()
{
sec++;
if (sec==122)
{
sec=0;
min--;
}
....
#int_timer2 // -- timer 2
void timer2_isr(void)
{
if (Miliseconds < 0xFF)
Miliseconds++;
if(miliTWO == 1000)
{
sekTwo ++;
}
if (sekTWO == 60 )
{
minTWO--;
}
....
main()
{
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
setup_timer_2(T2_DIV_BY_4,(8000000/80000),5);
enable_interrupts(INT_TIMER1);
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
}
-------------------------------------------------- | QUESTION1:
How to get wright calculation for timers(in my case)
QUESTION2
Wenn i enter some switch case option the "correct" time is displayed.
How to refresh the display( with new time ) when im still in the case option?. Ok i can do some for loop, but then, i don't know how long will
take for user to change the state / case.
TaiChipY |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Fri Apr 15, 2005 4:17 am |
|
|
Quote: | setup_timer_1(T1_INTERNAL|T1_DIV_BY_8); | Timer 1 is running at 8MHz / 4 instructions per clock / T1_DIV_BY_8 / 256 bitcounter = 976 interrupts/second. This is one interrupt every 1.0240 microseconds. A timing error of 1.44 seconds every minute.
Please post a small but complete program, for example all variable declarations are missing. Your timer1 is in miliseconds but you are only counting seconds in the timer1 interrupt so very likely you omitted some code here as well. The missing fuse settings often give helpfull information as well.
What compiler version are you using?
Yes, it's a lot of work to create a small demo program and to type in all the information. Just remember the easier you make life on us the faster and better reponses you will get. Right now with all above information missing I just refuse to spend more time looking for your bug. |
|
|
|
|
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
|