![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
STIX
Joined: 17 Jun 2006 Posts: 12
|
Timer Questions |
Posted: Wed Jul 12, 2006 9:48 am |
|
|
I have a couple of questions regarding the use of timers:
First, I want to read some sensor readings through the ADC for x amount of seconds. How do I use the timers to time my sensor reading period for the specified amount of time?
Second, I want to know how long it took for a sensor reading to occur. This is the opposite of what I wanted to do before. For example, when the sensor reading reaches a certain value, I want to read the timer so that I know the time it took for the event to happen.
I'm new to timers so I don't know if what I said is possible with the use of timers. If not, can anyone recommend something else to use? Thanks alot for your help. |
|
![](templates/subSilver/images/spacer.gif) |
rwyoung
Joined: 12 Nov 2003 Posts: 563 Location: Lawrence, KS USA
|
|
Posted: Wed Jul 12, 2006 1:28 pm |
|
|
A little clarifiacation:
Quote: | First, I want to read some sensor readings through the ADC for x amount of seconds. How do I use the timers to time my sensor reading period for the specified amount of time?
|
By this do you mean continuously read a sensor for X seconds or read a sensor once every X seconds? Both ways are doable.
The second item you ask about is possible.
One way would be to configure your timer for some reasonable resolution, some timers have prescalers. Clock the timer from the system clock. Then when you start your reading, read and remember the timer value. Then keep reading your ADC until you get your desired result. Read timer again. Caveat: timer can overflow and while you can detect and compensate for a single overflow with these two timer value reads, you can't tell the difference between one overflow and 100 overflows.
If your longest reading duration will guarantee multiple overflows, you should look at some of the real-time clock code on the forumn. You could modify it for the resolution you need and run the timer and its interrupt in the background to time your sensor's activity. _________________ Rob Young
The Screw-Up Fairy may just visit you but he has crashed on my couch for the last month! |
|
![](templates/subSilver/images/spacer.gif) |
STIX
Joined: 17 Jun 2006 Posts: 12
|
|
Posted: Wed Jul 12, 2006 1:47 pm |
|
|
Quote: | By this do you mean continuously read a sensor for X seconds. |
Yes, this is what I mean. Is the approach here to start the timer and then after x seconds, generate an interrupt? Can it be done without any interrupt? |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jul 12, 2006 4:40 pm |
|
|
You can poll an interrupt flag in a loop, to see if it's been set.
This way, you can tell if some hardware module has completed
an action, without having an isr. In some cases, this may be
an appropriate way to write the code. Here's an example
for the INT_EXT interrupt.
http://www.ccsinfo.com/forum/viewtopic.php?t=27167&start=4 |
|
![](templates/subSilver/images/spacer.gif) |
rwyoung
Joined: 12 Nov 2003 Posts: 563 Location: Lawrence, KS USA
|
|
Posted: Fri Jul 14, 2006 6:54 am |
|
|
STIX wrote: | Quote: | By this do you mean continuously read a sensor for X seconds. |
Yes, this is what I mean. Is the approach here to start the timer and then after x seconds, generate an interrupt? Can it be done without any interrupt? |
If your duration and timing resolution is on the order of seconds then I would look in the Code section of the forum for the real-time code modules. You can have that running in the background, read the time at start and loop on your sampling routine, always checking the latest time and drop out of the sample routine when appropriate.
If, for example, your sampling duration was 2 seconds and you were OK with 2.0 or 2.1 or 2.01 or maybe 2.001 then the above will probably work.
PCM's suggestion too look at the INT_EXT example is good so that you can see an alternative to using an interrupt. _________________ Rob Young
The Screw-Up Fairy may just visit you but he has crashed on my couch for the last month! |
|
![](templates/subSilver/images/spacer.gif) |
STIX
Joined: 17 Jun 2006 Posts: 12
|
|
Posted: Fri Jul 14, 2006 11:46 am |
|
|
I did some experimenting and wrote a simple program to read my temperature sensor (LM35) for a period of 12 sec. I'm using Timer1 and internal clock with a prescaler value of 8 (timer overflow every: 1/1MHz * 8 * 65536 = 0.52 sec). However, I'm having trouble with the ADC reading. It's not reading the correct value coming from the temperature sensor. I'm suppose to sense room temperature (ie 24.6°C) and store the value in the EEPROM. Afterwards, when I check the value in EEPROM, it's not the correct temperature reading. I should be getting something like 24.6, instead I get something like 252 stored in EEPROM. Furthermore, when I tried to sense a higher temperature than 24.6°C, I get a number like 237 stored in the EEPROM. I don't know what I'm doing wrong, are the interrupts interferring with the ADC?
I'm using the code in the following link to convert the HEX numbers in EEPROM to decimal numbers: http://www.ccsinfo.com/forum/viewtopic.php?t=1831&highlight=pconvert.
Code: | #include <16f877a>
#device *=16
#device ADC=10
#include <math>
#fuses HS,NOWDT,NOPUT,NOPROTECT,NODEBUG,BROWNOUT,NOLVP,NOCPD,NOWRT
#byte TRISA = 0x85
#byte TRISB = 0x86
#byte ADCON0 = 0x1F
#byte ADCON1 = 0x9F
#byte ADRESH = 0x1E
#byte ADRESL = 0x9E
#bit GO = ADCON0.2
float meas, ref;
int seconds_count;
int1 time_reached;
#int_timer1
void timer1_isr (void)
{
if (seconds_count++ == 23) //12/0.52 = 23
time_reached = 1;
}
void main (void)
{
TRISA = 0xff; //Pin AN0 on PORTA set as input
ADCON1 = 0x80; //Right justify result
seconds_count = 1;
time_reached = 0;
ref = 0.0;
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
set_timer1(0);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
while (time_reached == 0)
{
ADCON0 = 0; //Select AN0 input
ADCON0 = 0x41; //Turn A/D on in AN0, select FOSC/8 clock
meas = read_ad (0x45);
if (meas > ref)
ref = meas;
}
if (time_reached == 1)
write_eeprom_float(0, ref);
}
float read_ad (float chnl)
{
float temp;
long ad, v;
ADCON0 = chnl;
while (GO == 1);
ad = make16(ADRESH, ADRESL);
v = 5.0*ad*(100.0/1024.0); //Get actual temp. in °C
temp = (float)v;
return temp;
}
void write_eeprom_float (long int n, float data)
{
int i;
for (i = 0; i < 4; i++) {
write_eeprom(i + n, *(((int *)&data) + i));
}
return;
} |
|
|
![](templates/subSilver/images/spacer.gif) |
rwyoung
Joined: 12 Nov 2003 Posts: 563 Location: Lawrence, KS USA
|
|
Posted: Fri Jul 14, 2006 12:18 pm |
|
|
1) Don't bother with floating point. Store either as a fixed point (use 32 bits) or just store the RAW adc reading.
2) You don't need to build up your own version of the adc reading from the two bytes. Since you have specified #device ADC = 10 you will be getting back a 16 bit number from the built in (consult your manual) read_adc(). Use that instead.
3) You don't need to explicitly include a "return" statement in a void function (ie subroutine). The "return" statement is implicit.
4) Consult your manual for the functions used to configure the ADC and select channels. By using those you have more portability between parts. _________________ Rob Young
The Screw-Up Fairy may just visit you but he has crashed on my couch for the last month! |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|