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 CCS Technical Support

Help with Frequency Counter
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
marcus.couceiro



Joined: 04 Jan 2012
Posts: 12
Location: Brazil

View user's profile Send private message

Help with Frequency Counter
PostPosted: Wed Jan 04, 2012 6:25 am     Reply with quote

Dear All,

I am new to this PIC area so I would like to request your patience with my question.

I have been reading a lot of books regarding programming techniques and because of that tried to develop a small frequency counter myself.

I know we can find several programs around but my intention is learn the basics. So, here goes the problem:

Using PIC16F873 and Proteus simulator I have written the following code:
Code:

#include " 16F877A.h "
#use delay (clock=4000000)

int one_second;
long frequency;

#int_TIMER0
    void ISR_tmr0
       { one_second=one_secod++;
          clear_interrupt(INT_TIMER0);
       }

void main ()
   {

      while (1)

      setup_timer_0(T1_INTERNAL);
      setup_timer_1(T1_EXTERNAL | DIV_BY_1);
      enable_interrupts(GLOBAL);
      enable_interrupts(INT_TIMER0);

      if (one_second=3906)
         { frequency=get_timer1();
            set_timer1(0);
            set_timer0(0);
            clear_interrupt(INT_TIMER0);
         }

      putc(254);putc(1);delay_ms(500);
      printf("frequency:  %d Hz", frequency);
}

Despite the typo you might find above, compiler run without problems. When simulating in Proteus, I can see no errors and nothing showed on display.

Can anyone point out what I did wrong?

Tks
_________________
Marcus Couceiro
temtronic



Joined: 01 Jul 2010
Posts: 9241
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Jan 04, 2012 6:58 am     Reply with quote

What's wrong ...
You are using Proteus !!

Honestly, get rid of it! It is full of bugs, errors and does NOT work properly as a PIC simulator. A quick search of this forum will find HUNDREDS of 'it doesn't work in simulation' and ALL errors are due to the Proteus software, which we obviously cannot debug let alone fix.

Get some real PICs, a breadboard, cut code,burn the PIC, run, observe and learn from doing.Yes, 'old school' but you will LEARN how the PIC works and HOW to cut better code.

After 20+ years of using PICs , I still use this as my developement style.If it works on a breadboard , it'll work in a PCB.

As for your code...
putc(254);putc(1);delay_ms(500);
printf("frequency: %d Hz", frequency);
...
It looks like you're trying to send data to a 'serial LCD' module, but you haven't 'setup' the PIC right by telling it which pin the LCD is on or speed,etc. This would be the use rs232(...) and you'ld have to tell the printf(...) where to send the data as well.

If you press F11 while your project is open, the CCS C onscreen help manual comes up. Instant access to 99% of what you need to know.The rest is shown in the examples found in the 'examples' folder.
marcus.couceiro



Joined: 04 Jan 2012
Posts: 12
Location: Brazil

View user's profile Send private message

PostPosted: Wed Jan 04, 2012 7:14 am     Reply with quote

Thank you for your help Temtronic,

Although not shown, the #use RS232 line was included in the code. I do not believe this is the problem.

As for Proteus, I have been simulating small programs with it and never had any issue. Maybe if the programs get larger they will come up.

I also like the "old school" but I also think that I need to evolve to new technologies. If we can simulate if the bridge will break, why build it first?

Could you have a look at the code and see what I did wrong?

Thank you for your help?

Marcus
_________________
Marcus Couceiro
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Wed Jan 04, 2012 8:05 am     Reply with quote

do it for real - dump proteus....

but errors??
you got em!!!

1- you re init timers every time thru the while loop
2- NO brace after while stmt - hence the display stmt will not execute
3- you dont need to clear the timer int in the ISR - compiler does it for you
4-LOSE delay_ms(500)
and MANY more ......

why not INDENT your code and use the code button here ??

it would help you see what is wrong

you did not write CODE - you wrote disaster ........
temtronic



Joined: 01 Jul 2010
Posts: 9241
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Jan 04, 2012 8:11 am     Reply with quote

The reason for 'building the bridge'( good example !) instead of simulating..

In every Proteus schematic that I've seen posted here, several glaring errors appear even though the 'code' kinda works.
These errors which Proteus ignores but in the real world would be catastorphic include
1) No power to PIC power Vdd and Vss pins,never run in the real world
2) No crystal or caps to PIC xtal pins,never oscillate in the real world
3) NO regard to mismatched Vcc levels of PIC(5 V) to devices(3V)(classic !)
4) _mclr NOT tied high, yet PIC 'runs '.

'Old School' design means proper schematics that would be handed to a tech to wireup and test, then debug.While a seasoned tech would wire up Vdd and Vss,etc. a rookie, fresh out of school would follow the schematic 100% (to impress the boss) but it won't work as shown.


Just a sample of errors that if you built the PIC as shown in the schematic, it will never,ever work.Having 'blind faith' in a simulator is not a good idea. Several people have died due to faulty logic,based on bad simulators.Worst here is a blown PIC, in the real world planes have crashed( I'm also a pilot).

re: the ISR. You do not have to clear it, compiler does that for you.

If you need more help with the program, use the /code button when posting and be sure it's the complete(but small) compilable program. You should also say which PIC and version of the compiler.
marcus.couceiro



Joined: 04 Jan 2012
Posts: 12
Location: Brazil

View user's profile Send private message

PostPosted: Wed Jan 04, 2012 8:50 am     Reply with quote

Once again Temtronic, thank you for your help.

Asmboy, maybe you could read the first sentence after "Dear all,".

I am trying to learn so maybe instead of criticize only you could use all the knowledge it seems you have and teach everyone else in the right way.

I did not know how to use the "code" button. I will pay more attention in the future.

Now, I will remove the Clear_INT in the ISR routine and put the last brace of the IF routine after the printF command.

Asmboy, I have seen other codes where people re init timers thru the while loop. I assume this is wrong.

What do you mean with LOSE delay_ms(500)?

Can you point the MANY more errors so I can try to change from "disaster" to code?

Your help is appreciated.
_________________
Marcus Couceiro
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Wed Jan 04, 2012 10:46 am     Reply with quote

my best advice :

1- lose= GET rid of 500 msec delay
2- learn to solder and build something real,
as simulation is kid stuff and teaches the
unfortunate lesson that "wishes=fishes" -
when in reality , design is far more complex.

Proteus forgives much and teaches little IMHO

btw: i believe you posted here in SEARCH of criticism.
So as the wise man said,
" be careful what you wish for ....."

best of luck

Very Happy Very Happy
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Jan 04, 2012 12:46 pm     Reply with quote

Quote:
int one_second;
long frequency;

#int_TIMER0
void ISR_tmr0
{ one_second=one_secod++;
clear_interrupt(INT_TIMER0);
}

The line in bold above has a variable which has not been declared.
If it's a typo, it's still the wrong way to increment a variable in C.
Just doing this is sufficient:
Code:

one_second++;


Quote:

int one_second;

if (one_second=3906)
{ frequency=get_timer1();
set_timer1(0);
set_timer0(0);
clear_interrupt(INT_TIMER0);
}

Regarding the sections in bold above, in CCS, an 'int' is an unsigned 8-bit
integer. It's range is 0 to 255. If you want to go up to 3906, you need to
declare it as 'int16'.

I didn't look at your program design. Just at those coding bugs.
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Wed Jan 04, 2012 1:02 pm     Reply with quote

RE: STRUCTURE
Code:


unsigned int16 one_second=0;
unsigned int16 frequency=0;;

#int_TIMER0
    void ISR_tmr0{
    ++one_second         
  }

void main ()  {
      setup_timer_0(T1_INTERNAL);
      setup_timer_1(T1_EXTERNAL | DIV_BY_1);
      enable_interrupts(GLOBAL);
      enable_interrupts(INT_TIMER0);

      while (1){
   

      if (one_second==3906) {
            frequency=get_timer1();
            set_timer1(0);
            set_timer0(0);
            clear_interrupt(INT_TIMER0);
            putc(254);putc(1);
            printf("frequency:  %d Hz", frequency);
     }

      putc(254);putc(1);delay_ms(500);
      printf("frequency:  %d Hz", frequency);
}


that is STRUCTURE fixed a bit
one_second must be a misnomer ---
But w/o knowing the prescalar for timer 0 -??
you should specify it in the setup call--
this much i know - it is sure that the ISR is actually much faster
than "seconds" based on seat of pants math
( timer 0 ISR will be taken much too often 1/sec)
marcus.couceiro



Joined: 04 Jan 2012
Posts: 12
Location: Brazil

View user's profile Send private message

PostPosted: Wed Jan 04, 2012 2:42 pm     Reply with quote

Hi Guys,

Thank you so much for your help.

PCM programmer, I realized that if one_second was supposed to count until 3096 I would have to change its type but thanks anyway. I already implemented the changes you proposed below mixing them with the proposed changes from asmboy.

Asmboy,

Before seeing your post, I was trying to change the code so it could look better and easier to understand. Your comments were really helpful. I have also changed the variable one_second to flag (no problems with that).

Code:

#include <16F873.h>   // Specifies the uP to be used

#FUSES NOWDT   // Disable WatchDog Timer
#FUSES XT   // Use Crystal Oscillator
#FUSES PUT   // Enable Power On Timer
#FUSES NOPROTECT   // EPROM Not Protected
#FUSES NOLVP   // Disable Low Voltage programming
#FUSES NOCPD   // No Code Protection
   
#use delay(clock=4000000)   // Set Crystal Frequency
#use RS232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)   // Set RS232 Port Parameters


unsigned int16 flag=0;   // Variable to count the number of TIMER0 Interruptions, initially set to zero
unsigned int16 frequency=0;   // variable to hold the value from Timer1 set to zero

#int_TIMER0   // Timer0 Interruption
   
   void isr_timer0()   // Interrupt Service Request for Timer0
      {  ++flag;   // Add one to flag variable
      }

void main ()
{
   setup_TIMER_0(RTCC_INTERNAL | RTCC_DIV_1);   // Define TIMER0 as Internal timer (Fosc/4)
   setup_TIMER_1(T1_EXTERNAL | T1_DIV_BY_1);   //Define Timer1 as External, no pre-scaler   
   enable_interrupts(GLOBAL);   // Enable GLOBAL Interruptions
   enable_interrupts(INT_TIMER0);   // Enable TIMER0 Interruption
   set_TIMER0(0);      // Reset TIMER0
   set_TIMER1(0);      // Reset TIMER1
   

   while(1)   //*****************************************Endless Loop
      {
   IF (flag==3921);   // Count approx. 1s @ 4MHz (0.999855s)
      {   
   frequency=get_timer1();   // Stores the number of clocks received at TIMER1
   flag=0;   // Reset flag so it can start count to 3921 again
   set_TIMER0(0);   // Reset TIMER0
   clear_interrupt(INT_TIMER0);   // Clear INT_TIMER0
   set_TIMER1(0);   // Reset TIMER1
   putc(254);putc(1);delay_ms(10);   // Prepare display to receive data
   printf("frequency: %Ld Hz", frequency);   // Show frequency
   
      }
   }
}


Although it's not working yet, and already apologizing for using Proteus to simulate the program, I could see 145 Hz on the display (I am using 5Mhz as T1CKl).

I supposed that if you assign TIMER0 as RTCC_INTERNAL it would already be configured as Fosc/4 but after reading the Reference manual, I saw a note saying:

Note: To achieve a 1:1 prescaler assignment for the TMR0 register, assign the prescaler to the Watchdog Timer.

I have no idea on how to do that so I included a line stating that at setup_timer_0.

Once again thank you for your help. I will be waiting for your comments.
_________________
Marcus Couceiro
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Jan 04, 2012 2:48 pm     Reply with quote

Just a comment. The programming concept of a "flag" is a variable that
shows either of two binary states (True and False), or it's a byte that
has up to 8 flag bits in it (each one of those is True or False).

'Flag' is not an appropriate name for a variable that holds a count.
marcus.couceiro



Joined: 04 Jan 2012
Posts: 12
Location: Brazil

View user's profile Send private message

PostPosted: Thu Jan 05, 2012 3:59 am     Reply with quote

Hi PCM Programmer,

Thank you for the explanation. This was changed in the new version I will post when I get back home.

I was able to make the program work. The only limitation is that it can count until 35 kHz. Above that nothing changes.

I have changed the concept a little bit. Used TIMER0 to count the pulses and TIMER1 to count to 0.1s. When 0.1s reached there will be overflows on TIMER0 stored in another variable so I get the value at TIMER0, sum with the number of times we had overflow and multiply by 10.

Something like frequency=10((factor*255)+get_timer0()) where factor is the number of times we had overflow.

It worked but only till 35 kHz. I guess it's related to timing. Could anyone try to explain me the reason?

I will post the code by the end of the day.

Thank you all for your help.
_________________
Marcus Couceiro
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jan 05, 2012 1:39 pm     Reply with quote

Do you have to capture the frequency by this method ? Microchip put in
a CCP module to do most of the work for you in hardware.

Here are several threads that discuss using the CCP to capture the
frequency of an input signal:
http://www.ccsinfo.com/forum/viewtopic.php?t=33153
http://www.ccsinfo.com/forum/viewtopic.php?t=29963
http://www.ccsinfo.com/forum/viewtopic.php?t=36852
http://www.ccsinfo.com/forum/viewtopic.php?t=38013
marcus.couceiro



Joined: 04 Jan 2012
Posts: 12
Location: Brazil

View user's profile Send private message

PostPosted: Sat Jan 07, 2012 9:31 am     Reply with quote

Gentlemen,

Sorry for the delay. Busy Days!

Here is the code you helped me to write.
Code:
#include <16F873.h>   // Specifies the uP to be used

#FUSES NOWDT   // Disable WatchDog Timer
#FUSES XT   // Use Crystal Oscillator
#FUSES PUT   // Enable Power On Timer
#FUSES NOPROTECT   // EPROM Not Protected
#FUSES NOLVP   // Disable Low Voltage programming
#FUSES NOCPD   // No Code Protection
   
#use delay(clock=4000000)   // Set Crystal Frequency
#use RS232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)   // Set RS232 Port Parameters


unsigned int1 flag=0;   // Variable to indicate if 0.1 s a counted, initialy set to zero
unsigned int16 frequency=0, factor=0;   // variables to hold the value from Timer0 and multiplier factor, initially set to zero


#int_TIMER1   // Timer1 Interruption
   
   void isr_timer1()    // Interrupt Service Request for Timer1
      {  flag=1;        // Add one to flag variable
         
      }
     
#int_TIMER0
   void isr_timer0()    // Interrupt Service Request for Timer1
      {  factor++;      // add one to multiplier factor
      }

void main ()
{
   setup_TIMER_0(RTCC_DIV_1|RTCC_EXT_L_TO_H);   // Define TIMER0 as external counter
   setup_TIMER_1(T1_INTERNAL | T1_DIV_BY_8);   //Define Timer1 as Internal, pre-scaler set to 8   
   enable_interrupts(GLOBAL);   // Enable GLOBAL Interruptions
   enable_interrupts(INT_TIMER1);   // Enable TIMER1 Interruption
   enable_interrupts(INT_TIMER0);   // Enable TIMER0 Interruption

   set_TIMER1(53035);      // count 0.1s
   

   while(1)   //*****************************Endless Loop
      {
   IF (flag==1)   // IF 0.1s have passed....
      {   
      frequency=10*((factor*255)+get_TIMER0());   // Reads the value from Timer0, add the extra pulses and multiply by 10 (0.1s*10= 1s)
      flag=0;   // Reset flag so it can start count again
      set_TIMER0(0);   // Reset TIMER0
      factor=0;      // Reset Multiplier Factor
      set_TIMER1(53035); // Count 0.1s again
      putc(254);putc(1);putc(0);delay_ms(1);   // Prepare display to receive data
      printf("freq.: %Lu Hz", frequency);   // Show frequency
      }
   }
}


PCM programmer, thank you for the links. Using CCP seems much better. I will try to understand that. The code above counts up to 35K Hz but in the end I have 30 Hz errors (instead of 35000 it shows 34970).

Just for knowledge, does anyone know why it goes up to 35000 and not further?

Thank you all for sharing and helping me understand a little bit of C.

Regards
_________________
Marcus Couceiro
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Sat Jan 07, 2012 10:10 am     Reply with quote

comment

because you set flag in an ISR and the structure of your loop in MAIN --
essentially you are just polling "flag" but with the extra latency of of the ISR added on.

i think there would be less latency overhead if you declared
#Bit TMR1IF =gentenv(SFR:Tmr1if)

and then in your main loop simply made your conditional be
if (TMR1IF) {...

and add TMR1IF=0 after you re-init timer1 in the main conditional branch


i'm thinking - this IS a counter right? and any excess overhead is an error

oh yeah - enable global ints after ALL the individual INT enables -
NOT beforehand -
as to your max count limit ?
the way its coded makes my head hurt already .....
Shocked
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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