![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
Rollo Guest
|
16F877 timer1 reads vary? |
Posted: Thu Mar 27, 2003 10:45 pm |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
Tomi Guest
|
Re: 16F877 timer1 reads vary? |
Posted: Fri Mar 28, 2003 2:26 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
Rollo Guest
|
Re: 16F877 timer1 reads vary? |
Posted: Fri Mar 28, 2003 7:31 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
Tomi Guest
|
Re: 16F877 timer1 reads vary? |
Posted: Fri Mar 28, 2003 9:55 am |
|
|
<font face="Courier New" size=-1>Well, I didn't test that code 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 |
|
![](templates/subSilver/images/spacer.gif) |
Rollo Guest
|
Re: 16F877 timer1 reads vary? |
Posted: Fri Mar 28, 2003 2:50 pm |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
Re: 16F877 timer1 reads vary? |
Posted: Sat Mar 29, 2003 8:56 am |
|
|
:=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 _________________ Humber |
|
![](templates/subSilver/images/spacer.gif) |
Rollo Guest
|
Re: 16F877 timer1 reads vary? |
Posted: Sat Mar 29, 2003 8:25 pm |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
Re: 16F877 timer1 reads? |
Posted: Sat Mar 29, 2003 11:09 pm |
|
|
:=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 _________________ Humber |
|
![](templates/subSilver/images/spacer.gif) |
Rollo Guest
|
Re: 16F877 timer1 reads? |
Posted: Sun Mar 30, 2003 11:44 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
Rollo Guest
|
Found a very easy solution! Pulsewidth |
Posted: Sun Mar 30, 2003 1:00 pm |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
Re: 16F877 timer1 reads? |
Posted: Sun Mar 30, 2003 10:32 pm |
|
|
:=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 _________________ Humber |
|
![](templates/subSilver/images/spacer.gif) |
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
Re: Found a very easy solution! Pulsewidth |
Posted: Mon Mar 31, 2003 9:47 am |
|
|
:=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 |
|
![](templates/subSilver/images/spacer.gif) |
Rollo Guest
|
Re: Found a very easy solution! Pulsewidth |
Posted: Mon Mar 31, 2003 4:16 pm |
|
|
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 |
|
![](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
|