CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

16F877 timer1 reads vary?

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Rollo
Guest







16F877 timer1 reads vary?
PostPosted: Thu Mar 27, 2003 10:45 pm     Reply with quote

Trying to measure the time elapsed between two falling edges. I have tried many of the exmples either posted by members of this group, or from the examples directory. I am managing to get some readings using a variety of different strategies, but so far, in all cases, I get very unstable readings. I'm not sure why this is.

This lastest attempt builds on a posting by a member of this group ( Umberto? ). The data I expect should be fairly stable, but the data I get is not.

DATA in microsecs... 212, 118, 71, 118, 71, 212, 212, 118, 71 etc.

Something's wrong, but what? Here's the code adapted to my 16F877...

#include <16F877.H>
#fuses XT,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP
#use delay(clock=4000000) //using 4Mhz crystal you'll get 1 us increment
#include "lcd.c"

int16 counter;
int16 end_counter_ready, enable_counter;

void main()
{
lcd_init();
delay_ms(1000);
printf(lcd_putc, "Microsec");
enable_interrupts(INT_EXT);
setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_1 );
ext_int_edge(H_to_L);
enable_interrupts(GLOBAL);

while(TRUE)
{
if(end_counter_ready)
{
end_counter_ready = FALSE;
lcd_gotoxy(1,0);
printf(lcd_putc, "s= \%05lu", counter);
delay_ms(1000); // choose your update time interval
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
}

do
{

}while(enable_counter);
}
}


#int_EXT
edge_detect_isr()
{
if(!enable_counter) // first falling edge
{
enable_counter = TRUE;
enable_interrupts(INT_TIMER1);
set_timer1(0);
counter = 0;
}
else
{ // second falling edge
disable_interrupts(INT_TIMER1);
counter = get_timer1();
disable_interrupts(INT_EXT);
enable_counter = FALSE;
end_counter_ready = TRUE;
}
}
___________________________
This message was ported from CCS's old forum
Original Post ID: 13173
Tomi
Guest







Re: 16F877 timer1 reads vary?
PostPosted: Fri Mar 28, 2003 2:26 am     Reply with quote

Just another tip. Try this:

#include <16F877.h>
#use delay(clock=4000000) //using 4Mhz crystal you'll get 1 us increment
#include <lcd.c>

#fuses XT,WDT,PUT,PROTECT,NOBROWNOUT,NOLVP,NOCPD,NOWRT
#id 1,0,0,0

char myflags;
unsigned long speedcnt,speedcntX,sumcnt,sumcntX;
int32 actcnt32;

#byte speedL = speedcnt
#byte speedH = speedcnt + 1
#byte speedXL = speedcntX
#byte speedXH = speedcntX + 1
#byte sumcntL = sumcnt
#byte sumcntH = sumcnt + 1
#byte sumcntXL = sumcntX
#byte sumcntXH = sumcntX + 1
#byte actcnt32L = actcnt32
#byte actcnt32H = actcnt32 + 1
#byte actcnt32XL = actcnt32 + 2
#byte actcnt32XH = actcnt32 + 3

#bit NewMeas = myflags.0

#byte TREG1L = 0x0E
#byte TREG1H = 0x0F

#int_ext
void __EXTIT()
{
sumcntL = TREG1L;
TREG1L = 0;
sumcntH = TREG1H;
TREG1H = 0;
sumcntX = speedcntX;
NewMeas = 1;
}

#int_timer1
void __TMR1()
{
speedcntX++; // increment upper 16 bit of the counter
}


void main()
{

sumcnt = 0;
sumcntX = 0;
speedcntX = 0;
speedcntX = 0;

lcd_init();
delay_ms(1000);
printf(lcd_putc, "Microsec");

Port_B_pullups(TRUE);
ext_int_edge(L_TO_H);
setup_counters(RTCC_INTERNAL,RTCC_DIV_256);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
TREG1L = 0;
TREG1H = 0;
myflags = 0;
enable_interrupts(INT_TIMER1);
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
while (1) {
Restart_wdt();
if (NewMeas) {
actcnt32L = sumcntL;
actcnt32H = sumcntH;
actcnt32XL = sumcntXL;
actcnt32XH = sumcntXH;
actcnt32 += 4; // timer1 correction
lcd_gotoxy(1,0);
printf(lcd_putc, "s= \%lu", actcnt32);
NewMeas = 0;
}
}
}
___________________________
This message was ported from CCS's old forum
Original Post ID: 13177
Rollo
Guest







Re: 16F877 timer1 reads vary?
PostPosted: Fri Mar 28, 2003 7:31 am     Reply with quote

Thanks for taking the trouble to post that code, Tomi. So far, can't get it to work.

I compiled it without any changes, and then ran it. It did not output anything except the word "microsec" on the lefthand side of my LCD. I am using the exact same LCD code to output elsewhere, but in this case it shows nothing.

Interesting code!

I read it again and again trying to see which pin you are polling, if any? I have to admit I'm puzzled by your code, as I only have a vague idea what you're up to. Is this code to measure acceleration on something? It looks like port B is involved due to the pullups command. It also looks like to use two int16 to make up one int32, so I figure that has something to do with the Timer1 registers I read about in the datasheet for the 16F877.

I sure wish I could get the code to do something, as I'm now fairly curious to see what it's all about. I appreciate that you took the time to post it, but unfortunately I seem to be doing something wrong, since it does not seem to output anything.

Thanks again,
Rol




:=Just another tip. Try this:
:=
:=#include <16F877.h>
:=#use delay(clock=4000000) //using 4Mhz crystal you'll get 1 us increment
:=#include <lcd.c>
:=
:=#fuses XT,WDT,PUT,PROTECT,NOBROWNOUT,NOLVP,NOCPD,NOWRT
:=#id 1,0,0,0
:=
:=char myflags;
:=unsigned long speedcnt,speedcntX,sumcnt,sumcntX;
:=int32 actcnt32;
:=
:=#byte speedL = speedcnt
:=#byte speedH = speedcnt + 1
:=#byte speedXL = speedcntX
:=#byte speedXH = speedcntX + 1
:=#byte sumcntL = sumcnt
:=#byte sumcntH = sumcnt + 1
:=#byte sumcntXL = sumcntX
:=#byte sumcntXH = sumcntX + 1
:=#byte actcnt32L = actcnt32
:=#byte actcnt32H = actcnt32 + 1
:=#byte actcnt32XL = actcnt32 + 2
:=#byte actcnt32XH = actcnt32 + 3
:=
:=#bit NewMeas = myflags.0
:=
:=#byte TREG1L = 0x0E
:=#byte TREG1H = 0x0F
:=
:=#int_ext
:=void __EXTIT()
:={
:= sumcntL = TREG1L;
:= TREG1L = 0;
:= sumcntH = TREG1H;
:= TREG1H = 0;
:= sumcntX = speedcntX;
:= NewMeas = 1;
:=}
:=
:=#int_timer1
:=void __TMR1()
:={
:=speedcntX++; // increment upper 16 bit of the counter
:=}
:=
:=
:=void main()
:={
:=
:=sumcnt = 0;
:=sumcntX = 0;
:=speedcntX = 0;
:=speedcntX = 0;
:=
:=lcd_init();
:=delay_ms(1000);
:=printf(lcd_putc, "Microsec");
:=
:=Port_B_pullups(TRUE);
:=ext_int_edge(L_TO_H);
:=setup_counters(RTCC_INTERNAL,RTCC_DIV_256);
:=setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
:=TREG1L = 0;
:=TREG1H = 0;
:=myflags = 0;
:=enable_interrupts(INT_TIMER1);
:=enable_interrupts(INT_EXT);
:=enable_interrupts(GLOBAL);
:=while (1) {
:= Restart_wdt();
:= if (NewMeas) {
:= actcnt32L = sumcntL;
:= actcnt32H = sumcntH;
:= actcnt32XL = sumcntXL;
:= actcnt32XH = sumcntXH;
:= actcnt32 += 4; // timer1 correction
:= lcd_gotoxy(1,0);
:= printf(lcd_putc, "s= \%lu", actcnt32);
:= NewMeas = 0;
:= }
:=}
:=}
___________________________
This message was ported from CCS's old forum
Original Post ID: 13194
Tomi
Guest







Re: 16F877 timer1 reads vary?
PostPosted: Fri Mar 28, 2003 9:55 am     Reply with quote

<font face="Courier New" size=-1>Well, I didn't test that code Smile just copied some parts from my frequency meter.
Basically, because you wrote your task is to measure the elapsed time between two consecutive rising edges the snippet does:
- Clear Timer1 at startup, setup it to 1MHz internal input.
- On timer1 IT handler, increment the upper 16 bit of a 32-bit register. This is because you want to measure up to 10 sec in usec resolution so it could be up to 10,000,000.
- wait an interrupt on PIN_B0 (EXT_IT). This is the polled pin.
- In ext_it ISR copy the 32 bit counter (lower 16 bit is the actual Timer1 value) into a register to save it, clear Timer1 (and its upper 16 bit extension, oops, maybe this completely missing, insert a "speedcntX = 0" just after the line "sumcntX = speedcntX;") and set a bit "Measure Done".
- In the main() wait for "Measure Done" bit. If it is set, save the 32bit saved var and display this second copy. This double copy is necessary because you can get one or more additional EXT_IT under the printout (unless you disable any further ITs under printout) so the original saved value could be updated.
- After printout, clear MeasDone flag to enable the new printing.

Note: the 2nd line could be empty if you didn't connect the input frequency to pin_b0 OR if you have a higher frequency signal. Insert a delay_ms(200) just before "NewMeas = 0;" to limit the printouts to 5/seconds.
</font>
___________________________
This message was ported from CCS's old forum
Original Post ID: 13204
Rollo
Guest







Re: 16F877 timer1 reads vary?
PostPosted: Fri Mar 28, 2003 2:50 pm     Reply with quote

You're very kind to try to help me this way. However, since I can't yet, as a microchip beginner, understand your code well enough to make the adaptations you suggest, I will have to keep looking at it, one line at a time, and try to understand. If I can see how it works, then I might be able to execute what you're recommending.

It sounds like you do have the solution I seek, but I think it's just beyond my reach, at this point, and I don't quite fully understand how to adapt the code so it works.

Thanks very much for trying, tho'.

Rol

Rol


:=<font face="Courier New" size=-1>Well, I didn't test that code <img src="http://www.ccsinfo.com/pix/forum/smile.gif" border="0"> just copied some parts from my frequency meter.
:=Basically, because you wrote your task is to measure the elapsed time between two consecutive rising edges the snippet does:
:=- Clear Timer1 at startup, setup it to 1MHz internal input.
:=- On timer1 IT handler, increment the upper 16 bit of a 32-bit register. This is because you want to measure up to 10 sec in usec resolution so it could be up to 10,000,000.
:=- wait an interrupt on PIN_B0 (EXT_IT). This is the polled pin.
:=- In ext_it ISR copy the 32 bit counter (lower 16 bit is the actual Timer1 value) into a register to save it, clear Timer1 (and its upper 16 bit extension, oops, maybe this completely missing, insert a "speedcntX = 0" just after the line "sumcntX = speedcntX;") and set a bit "Measure Done".
:=- In the main() wait for "Measure Done" bit. If it is set, save the 32bit saved var and display this second copy. This double copy is necessary because you can get one or more additional EXT_IT under the printout (unless you disable any further ITs under printout) so the original saved value could be updated.
:=- After printout, clear MeasDone flag to enable the new printing.
:=
:=Note: the 2nd line could be empty if you didn't connect the input frequency to pin_b0 OR if you have a higher frequency signal. Insert a delay_ms(200) just before "NewMeas = 0;" to limit the printouts to 5/seconds.
:=</font>
___________________________
This message was ported from CCS's old forum
Original Post ID: 13216
Humberto



Joined: 08 Sep 2003
Posts: 1215
Location: Buenos Aires, La Reina del Plata

View user's profile Send private message

Re: 16F877 timer1 reads vary?
PostPosted: Sat Mar 29, 2003 8:56 am     Reply with quote

:=You're very kind to try to help me this way. However, since I can't yet, as a microchip beginner, understand your code well enough to make the adaptations you suggest, I will have to keep looking at it, one line at a time, and try to understand. If I can see how it works, then I might be able to execute what you're recommending.
:=
:=It sounds like you do have the solution I seek, but I think it's just beyond my reach, at this point, and I don't quite fully understand how to adapt the code so it works.
:=
:=Thanks very much for trying, tho'.
:=
:=Rol
:=
:=Rol
:=
:=
:=:=<font face="Courier New" size=-1>Well, I didn't test that code <img src="http://www.ccsinfo.com/pix/forum/smile.gif" border="0"> just copied some parts from my frequency meter.
:=:=Basically, because you wrote your task is to measure the elapsed time between two consecutive rising edges the snippet does:
:=:=- Clear Timer1 at startup, setup it to 1MHz internal input.
:=:=- On timer1 IT handler, increment the upper 16 bit of a 32-bit register. This is because you want to measure up to 10 sec in usec resolution so it could be up to 10,000,000.
:=:=- wait an interrupt on PIN_B0 (EXT_IT). This is the polled pin.
:=:=- In ext_it ISR copy the 32 bit counter (lower 16 bit is the actual Timer1 value) into a register to save it, clear Timer1 (and its upper 16 bit extension, oops, maybe this completely missing, insert a "speedcntX = 0" just after the line "sumcntX = speedcntX;") and set a bit "Measure Done".
:=:=- In the main() wait for "Measure Done" bit. If it is set, save the 32bit saved var and display this second copy. This double copy is necessary because you can get one or more additional EXT_IT under the printout (unless you disable any further ITs under printout) so the original saved value could be updated.
:=:=- After printout, clear MeasDone flag to enable the new printing.
:=:=
:=:=Note: the 2nd line could be empty if you didn't connect the input frequency to pin_b0 OR if you have a higher frequency signal. Insert a delay_ms(200) just before "NewMeas = 0;" to limit the printouts to 5/seconds.
:=:=</font>


Hi:

Iīm sure the code sent by Tomi has good accuracy and had been well matured, but probably it isnīt good for learning purposes, taking in mind that you are a beginner in this "sands".
I posted an example code a week before dealing with the same matter. It's not so thigth as Tomi's code but is easy to understand.

regards,

Humberto
___________________________
This message was ported from CCS's old forum
Original Post ID: 13229
_________________
Humberto
Rollo
Guest







Re: 16F877 timer1 reads vary?
PostPosted: Sat Mar 29, 2003 8:25 pm     Reply with quote

Hello Humberto. Thanks for the posting.

I read your code a few days ago, and even made a copy and tried to run it on my 16F877 PIC @ 4Mhz. However, I could not clearly understand which pin your code was polling. I assumed the rs232 was just for output to serial port. I have no such output and instead use an lcd with include lcd.c

Anyway, here's what I ended up with, of your code. I haven't been able to get it to work. Maybe I fiddled too much? ;-)
Anyways, would you maybe be able to tell me which pin is getting polled?

Here's that code of your ( modified )...

#include <16F877.H>
#fuses XT,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP
#use delay(clock=4000000)
#include <lcd.c>

int16 counter;
int16 end_counter_ready, enable_counter;

void main()
{
lcd_init();
delay_ms(1000);
printf(lcd_putc, "Microsec");

enable_interrupts(INT_EXT);
setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_1 );
ext_int_edge(H_to_L);
enable_interrupts(GLOBAL);

while(TRUE)
{
if(end_counter_ready)
{
end_counter_ready = FALSE;
lcd_gotoxy(1,0);
printf(lcd_putc, "s= \%05lu", counter);
delay_ms(1000); enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
}

do
{

}while(enable_counter);
}
}


#int_EXT
edge_detect_isr()
{
if(!enable_counter) // first falling edge
{
enable_counter = TRUE;
enable_interrupts(INT_TIMER1);
set_timer1(0);
counter = 0;
}
else
{ // second falling edge
disable_interrupts(INT_TIMER1);
counter = get_timer1();
disable_interrupts(INT_EXT);
enable_counter = FALSE;
end_counter_ready = TRUE;
}
}

Thanks,
Rol
___________________________
This message was ported from CCS's old forum
Original Post ID: 13231
Humberto



Joined: 08 Sep 2003
Posts: 1215
Location: Buenos Aires, La Reina del Plata

View user's profile Send private message

Re: 16F877 timer1 reads?
PostPosted: Sat Mar 29, 2003 11:09 pm     Reply with quote

:=Hello Humberto. Thanks for the posting.
:=
:=I read your code a few days ago, and even made a copy and
:= tried to run it on my 16F877 PIC @ 4Mhz. However, I could
:= not clearly understand which pin your code was polling. I
:= assumed the rs232 was just for output to serial port. I
:= have no such output and instead use an lcd with include lcd.c

I assume that the signal pulses is wired to PIN_B0 wich is the only pin available that can trigger the EXT_INT (this is a hardware feature of the PIC microcontroller, you donīt have another PIN to select) as defined in the datasheet.

:=Anyway, here's what I ended up with, of your code. I
:=haven't been able to get it to work. Maybe I fiddled too
:=much? ;-)
:=Anyways, would you maybe be able to tell me which pin is
:=getting polled?
_____ ________________________ ________________
PIN_B0 |_| |_|

:=Here's that code of your ( modified )...
:=
:=#include <16F877.H>
:=#fuses XT,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP
#use delay(clock=16000000)
:=#include <lcd.c>
#zero_ram;

:=int16 counter;
Yes, you need 16 bit here to make a copy of TIMER1 wich is a 16 BIT wide counter/timer.
With an internal clock at 16Mhz, the timer will increment every 2.0us and will overflow every 131.072ms, so be carefull because after that, the counter start counting again without giving you any "warning".

:=int16 end_counter_ready, enable_counter;
No, 16 Bit NOT necessary, such register are used like flags.
int end_counter_ready, counter_enabled;

#define signal_pulses PIN_B0
// You must declare as input when you set the TRIS registers
set_tris_B(0bxxxxxxx1); // x = 0 = OUTPUT x = 1 = INPUT

:=void main()
:={
:= lcd_init();
:= delay_ms(1000);
:= printf(lcd_putc, "Microsec");
:=
:= enable_interrupts(INT_EXT);
:= setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_1 );
:= ext_int_edge(H_to_L);
:= enable_interrupts(GLOBAL);
:=
while(TRUE)
{
if(end_counter_ready)
{
lcd_gotoxy(1,0);
printf(lcd_putc, "s= \%05lu", counter);
counter_enabled = FALSE;
end_counter_ready = FALSE;
delay_ms(1000);
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
}
else
{
lcd_gotoxy(1,0);
printf(lcd_putc, "Measuring..");
}

do
{
// Wait in this loop
}while(!end_counter_ready);
}
}

You didnīt mention how are the pulses shape you are dealing with, so I assume that the falling pulses are very short
(<100usec).
As configured, PIN_B0 iddle state must be High. Once enabled
INT_EXT, the first falling edge of the input signal will trigger the external interrupt, wich handler I named:
void edge_detect_isr()

#int_EXT
void edge_detect_isr()
{
if(!counter_enabled)// first falling edge pass through
{ // because counter_enabled is FALSE
enable_interrupts(INT_TIMER1);
set_timer1(0); // reset the counter
}
else // second falling edge pass through
{ // because counter_enabled become TRUE
// in the TIMER1 interrupt handler
disable_interrupts(INT_TIMER1);
counter = get_timer1(); // Make a copy of TIMER1
disable_interrupts(INT_EXT);
end_counter_ready = TRUE;
}
}
#int_timer1
void timer1_isr()
{
counter_enabled = TRUE;
}


Good wishes

Humberto
___________________________
This message was ported from CCS's old forum
Original Post ID: 13232
_________________
Humberto
Rollo
Guest







Re: 16F877 timer1 reads?
PostPosted: Sun Mar 30, 2003 11:44 am     Reply with quote

Humberto,

Wow! This code, especially with your step by step annotation, is much easier for me to understand. I can really see how it should work based on the code and clear explanations. However, it still does not seem to work correctly.

I had to change the code for my 16F877 4Mhz instead of 16Mhz.
With H_to_L, it did not output anything except the text message. An oscilloscope shows the output of the TSL230BR light sensor chip is a square wave, but it's low most of the time and then high for a short time. So I changed your H_to_L and replaced it with a L_to_H.

Now I am getting some data, but again, the data varies alot.
Example data, looking at it just now:

152, 490, 265, 169, 718, 651, 661, 133

As you can see the data really varies. However, the oscilloscope shows the pattern is very stable and the pulse widths are regular, repetitive and steady. So the data should also be that way, I expected.

I do have code that uses an interrupt to count to one second, and in that time I count pulses. The results with that code are also very steady, plus, they match results from a cicuit based on Basic Stamp 2 that uses this light sensor chip, and another circuit based on a Laptop and gnu C that uses the same light sensor chip. The Laptop version measures pulsewidths and gives same results ( when changed to Hz ) as the Basic Stamp version that just counts pulses. Bottom line: I therefore tend to think that my PIC 16F877 circuit and the TSL230BR chip are probably both configured correctly.

But I can't seem to get a steady pulsewidth measure using Timer1 and ext pulse measuring, as you suggested. Wasn't there a note somewhere about timer1 and ext clock problems?

In any case, Humberto, thanks very much for all your efforts. It was great, as you can imagine, working with your annotated code -- at least I see how it should behave, IF it were behaving. ;-)

Thanks!
Rol

P.S. - I re-copy your code, as adapted to my kit...

#include <16F877.H>
#fuses XT,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP
#use delay(clock=4000000)
#include <lcd.c>
#zero_ram


int end_counter_ready, counter_enabled;
int16 counter;
#define signal_pulses PIN_B0



set_tris_B(0b11111111);

void main()
{
lcd_init();
delay_ms(1000);
printf(lcd_putc, "Microsec");

enable_interrupts(INT_EXT);
setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_1 );
ext_int_edge(L_to_H );
enable_interrupts(GLOBAL);

while(TRUE)
{
if(end_counter_ready)
{
lcd_gotoxy(1,0);
printf(lcd_putc, "s= \%05lu", counter);
counter_enabled = FALSE;
end_counter_ready = FALSE;
delay_ms(1000);
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
}
else
{
lcd_gotoxy(1,1);
printf(lcd_putc, "Measuring..");
}

do
{

}while(!end_counter_ready);
}
}



#int_EXT
void edge_detect_isr()
{
if(!counter_enabled)
{
enable_interrupts(INT_TIMER1);
set_timer1(0);
}
else
{

disable_interrupts(INT_TIMER1);
counter = get_timer1();
disable_interrupts(INT_EXT);
end_counter_ready = TRUE;
}
}

#int_timer1
void timer1_isr()
{
counter_enabled = TRUE;
}
___________________________
This message was ported from CCS's old forum
Original Post ID: 13235
Rollo
Guest







Found a very easy solution! Pulsewidth
PostPosted: Sun Mar 30, 2003 1:00 pm     Reply with quote

Hi Humberto!

I have found a very easy solution to the pulsewidth problem. It's different than what you had posted, and it uses no interrupts. However, it gives accurate readings as compared to my BS2 and my friend's Laptop gnu C version.

I just sat down and wrote a "dumb as a doorknob" code, and I even called the filename "last_ditch_pulse.c". I never expected this to work, but it does! :->

Your code and excellent annotation showed me the logic, and I implemented that in the simplest way possible. The trick is to have all these while lines so as to account for all the possible starting points in the square curve. Once you're sure you're actually getting the leading edge ( instead of an interrupt to do this ), then you wait until the next leading edge and catch the timer1 value, as you showed me.

As I said, I didn't think such a simple approach would work but it does. My chip is 4 Mhz, so I just assumed that each timer1 click would be clock/4 which is 1000000th of a second or 1 usec.

Then I just did the math to turn this into Hertz. I tried it at a variety of light levels and it is very consistant with my other sensor circuits against which I am testing.

Thank so much for your assistance!

Cheers!
Rol


#include <16F877.H>
#fuses XT,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP
#use delay(clock=4000000)
#include "lcd.c" // include lcd.c

set_tris_B(1);
long pulses;
float hertz;

void main()
{
lcd_init();
delay_ms(1000);

setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_1 ); // setup time scale
do {

while( input(PIN_B7)); // if now already up, wait...
while(!input(PIN_B7)); // if now already down, wait...
while( input(PIN_B7)); // if going from down to up.
set_timer1(0); // set timer to zero
while(!input(PIN_B7)); // if low now.. wait
while( input(PIN_B7)); // if high a second time, get time elapsed from timer.

pulses = get_timer1();

hertz = (float) pulses / 1000000; // turn to floating point value
hertz = 1/hertz; // and transform to Hertz from pulsewidth

lcd_gotoxy(1,1);
printf(lcd_putc, "\%f\n Hertz ", hertz);
delay_ms(2000);

} while(true);
}
___________________________
This message was ported from CCS's old forum
Original Post ID: 13238
Humberto



Joined: 08 Sep 2003
Posts: 1215
Location: Buenos Aires, La Reina del Plata

View user's profile Send private message

Re: 16F877 timer1 reads?
PostPosted: Sun Mar 30, 2003 10:32 pm     Reply with quote

:=Humberto,
:=
:=Wow! This code, especially with your step by step annotation, is much easier for me to understand. I can really see how it should work based on the code and clear explanations. However, it still does not seem to work correctly.
:=
:=I had to change the code for my 16F877 4Mhz instead of 16Mhz.
:=With H_to_L, it did not output anything except the text message. An oscilloscope shows the output of the TSL230BR light sensor chip is a square wave, but it's low most of the time and then high for a short time. So I changed your H_to_L and replaced it with a L_to_H.
:=
:=Now I am getting some data, but again, the data varies alot.
:=Example data, looking at it just now:
:=
:=152, 490, 265, 169, 718, 651, 661, 133

May be TIMER1 overflow (????)

:=As you can see the data really varies. However, the oscilloscope shows the pattern is very stable and the pulse widths are regular, repetitive and steady. So the data should also be that way, I expected.
:=
:=I do have code that uses an interrupt to count to one second, and in that time I count pulses. The results with that code are also very steady, plus, they match results from a cicuit based on Basic Stamp 2 that uses this light sensor chip, and another circuit based on a Laptop and gnu C that uses the same light sensor chip. The Laptop version measures pulsewidths and gives same results ( when changed to Hz ) as the Basic Stamp version that just counts pulses. Bottom line: I therefore tend to think that my PIC 16F877 circuit and the TSL230BR chip are probably both configured correctly.
:=
:=But I can't seem to get a steady pulsewidth measure using Timer1 and ext pulse measuring, as you suggested. Wasn't there a note somewhere about timer1 and ext clock problems?

Yes, it's true. It refers to a silicon problem regarding TIMER1 clocked externally, BUT this is not the case, you will see in:

setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_1 );

where clearly timer1 is clocked internally.

:=In any case, Humberto, thanks very much for all your efforts. It was great, as you can imagine, working with your annotated code -- at least I see how it should behave, IF it were behaving. ;-)
:=
:=Thanks!
:=Rol
:=
:=P.S. - I re-copy your code, as adapted to my kit...
:=
:=#include <16F877.H>
:=#fuses XT,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP
:=#use delay(clock=4000000)
:=#include <lcd.c>
:=#zero_ram
:=
:=
:=int end_counter_ready, counter_enabled;
:=int16 counter;
:=#define signal_pulses PIN_B0
:=
:=
:=
:=set_tris_B(0b11111111);
:=
:=void main()
:={
:= lcd_init();
:= delay_ms(1000);
:= printf(lcd_putc, "Microsec");
:=
:= enable_interrupts(INT_EXT);
:= setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_1 );
:= ext_int_edge(L_to_H );
:= enable_interrupts(GLOBAL);
:=
:= while(TRUE)
:= {
:= if(end_counter_ready)
:= {
:= lcd_gotoxy(1,0);
:= printf(lcd_putc, "s= \%05lu", counter);
:= counter_enabled = FALSE;
:= end_counter_ready = FALSE;
:= delay_ms(1000);
:= enable_interrupts(INT_EXT);
:= enable_interrupts(GLOBAL);
:= }
:= else
:= {
:= lcd_gotoxy(1,1);
:= printf(lcd_putc, "Measuring..");
:= }
:=
:= do
:= {
:=
:= }while(!end_counter_ready);
:= }
:=}
:=
:=
:=
:=#int_EXT
:=void edge_detect_isr()
:={
:= if(!counter_enabled)
:= {
:= enable_interrupts(INT_TIMER1);
:= set_timer1(0);
:= }
:= else
:= {
:=
:= disable_interrupts(INT_TIMER1);
:= counter = get_timer1();
:= disable_interrupts(INT_EXT);
:= end_counter_ready = TRUE;
:= }
:=}
:=
:=#int_timer1
:=void timer1_isr()
:={
:= counter_enabled = TRUE;
:=}
:=
:=

I want you know that it was a pleasure to help you. It was my intention not to solve all your problems but to help you to understand how to handle them.
The beatifull of C languaje is that it give you a lot of ways to find the answer. Experience will teach you whatīs the best!!

Sorry for my english,

good wishes

Humberto



___________________________
This message was ported from CCS's old forum
Original Post ID: 13243
_________________
Humberto
Neutone



Joined: 08 Sep 2003
Posts: 839
Location: Houston

View user's profile Send private message

Re: Found a very easy solution! Pulsewidth
PostPosted: Mon Mar 31, 2003 9:47 am     Reply with quote

:=Hi Humberto!
:=
:=I have found a very easy solution to the pulsewidth problem. It's different than what you had posted, and it uses no interrupts. However, it gives accurate readings as compared to my BS2 and my friend's Laptop gnu C version.
:=
:=I just sat down and wrote a "dumb as a doorknob" code, and I even called the filename "last_ditch_pulse.c". I never expected this to work, but it does! :->
:=
:=Your code and excellent annotation showed me the logic, and I implemented that in the simplest way possible. The trick is to have all these while lines so as to account for all the possible starting points in the square curve. Once you're sure you're actually getting the leading edge ( instead of an interrupt to do this ), then you wait until the next leading edge and catch the timer1 value, as you showed me.
:=
:=As I said, I didn't think such a simple approach would work but it does. My chip is 4 Mhz, so I just assumed that each timer1 click would be clock/4 which is 1000000th of a second or 1 usec.
:=
:=Then I just did the math to turn this into Hertz. I tried it at a variety of light levels and it is very consistant with my other sensor circuits against which I am testing.
:=
:=Thank so much for your assistance!
:=
:=Cheers!
:=Rol
:=
:=
:=#include <16F877.H>
:=#fuses XT,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP
:=#use delay(clock=4000000)
:=#include "lcd.c" // include lcd.c
:=
:=set_tris_B(1);
:=long pulses;
:=float hertz;
:=
:=void main()
:={
:= lcd_init();
:= delay_ms(1000);
:=
:= setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_1 ); // setup time scale
:= do {
:=
:= while( input(PIN_B7)); // if now already up, wait...
:= while(!input(PIN_B7)); // if now already down, wait...
:= while( input(PIN_B7)); // if going from down to up.
:= set_timer1(0); // set timer to zero
:= while(!input(PIN_B7)); // if low now.. wait
:= while( input(PIN_B7)); // if high a second time, get time elapsed from timer.
:=
:= pulses = get_timer1();
:=
:= hertz = (float) pulses / 1000000; // turn to floating point value
:= hertz = 1/hertz; // and transform to Hertz from pulsewidth
:=
:= lcd_gotoxy(1,1);
:= printf(lcd_putc, "\%f\n Hertz ", hertz);
:= delay_ms(2000);
:=
:= } while(true);
:=}

It's good to hear you have things working like you want. Pulsewidth is the on time in a cycle period. What you are really measuring with this code posted is the cycle period. I can see now how all the proposed solutions would fail to work like you wanted because they all measured the pulsewidth.
___________________________
This message was ported from CCS's old forum
Original Post ID: 13254
Rollo
Guest







Re: Found a very easy solution! Pulsewidth
PostPosted: Mon Mar 31, 2003 4:16 pm     Reply with quote

Thanks Humberto, Tomi & Neutone.

Yes, now that you say it, I needed to measure the period of a pulse, though I didn't see that clearly until just now. In this astronomy light sensor, the square wave pulse looks like 10\% up and 90\% down, in the interesting range. The puslewidth for the up or down part only, was insufficient for me to get a good reading, it turns out. Only the total of one period, from one up edge to the next up edge, gave me accurate results that compared with the other units.

I just got my programmer and CCS a couple of weeks ago! Already, I have a dark sky sensor for which the parts cost maybe $20, as compared to a BS2 with B.O.E. or worse, a laptop with an external board thru the parallel port. I'm still early enough in the game that I'm finding this just amazing.

However, the help I got here, every step of the way was also amazing.

My Thanks!
Rol


:=:=Hi Humberto!
:=:=
:=:=I have found a very easy solution to the pulsewidth problem. It's different than what you had posted, and it uses no interrupts. However, it gives accurate readings as compared to my BS2 and my friend's Laptop gnu C version.
:=:=
:=:=I just sat down and wrote a "dumb as a doorknob" code, and I even called the filename "last_ditch_pulse.c". I never expected this to work, but it does! :->
:=:=
:=:=Your code and excellent annotation showed me the logic, and I implemented that in the simplest way possible. The trick is to have all these while lines so as to account for all the possible starting points in the square curve. Once you're sure you're actually getting the leading edge ( instead of an interrupt to do this ), then you wait until the next leading edge and catch the timer1 value, as you showed me.
:=:=
:=:=As I said, I didn't think such a simple approach would work but it does. My chip is 4 Mhz, so I just assumed that each timer1 click would be clock/4 which is 1000000th of a second or 1 usec.
:=:=
:=:=Then I just did the math to turn this into Hertz. I tried it at a variety of light levels and it is very consistant with my other sensor circuits against which I am testing.
:=:=
:=:=Thank so much for your assistance!
:=:=
:=:=Cheers!
:=:=Rol
:=:=
:=:=
:=:=#include <16F877.H>
:=:=#fuses XT,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP
:=:=#use delay(clock=4000000)
:=:=#include "lcd.c" // include lcd.c
:=:=
:=:=set_tris_B(1);
:=:=long pulses;
:=:=float hertz;
:=:=
:=:=void main()
:=:={
:=:= lcd_init();
:=:= delay_ms(1000);
:=:=
:=:= setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_1 ); // setup time scale
:=:= do {
:=:=
:=:= while( input(PIN_B7)); // if now already up, wait...
:=:= while(!input(PIN_B7)); // if now already down, wait...
:=:= while( input(PIN_B7)); // if going from down to up.
:=:= set_timer1(0); // set timer to zero
:=:= while(!input(PIN_B7)); // if low now.. wait
:=:= while( input(PIN_B7)); // if high a second time, get time elapsed from timer.
:=:=
:=:= pulses = get_timer1();
:=:=
:=:= hertz = (float) pulses / 1000000; // turn to floating point value
:=:= hertz = 1/hertz; // and transform to Hertz from pulsewidth
:=:=
:=:= lcd_gotoxy(1,1);
:=:= printf(lcd_putc, "\%f\n Hertz ", hertz);
:=:= delay_ms(2000);
:=:=
:=:= } while(true);
:=:=}
:=
:=It's good to hear you have things working like you want. Pulsewidth is the on time in a cycle period. What you are really measuring with this code posted is the cycle period. I can see now how all the proposed solutions would fail to work like you wanted because they all measured the pulsewidth.
___________________________
This message was ported from CCS's old forum
Original Post ID: 13266
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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