Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

frequency counter (using timer1 and CCP module)

Status
Not open for further replies.

israel_Y

Member level 1
Member level 1
Joined
Feb 8, 2010
Messages
34
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,286
Location
The Netherlands
Visit site
Activity points
1,534
I m writing frequency counter for 16f877A using mikroc: my code is seen below. please guide me where it is wrong as it doesnt give any output when i run it in proteus.

Code:
// Define LCD module connections.
 sbit LCD_RS at RD1_bit;
 sbit LCD_EN at RD0_bit;
 sbit LCD_D4 at RD4_bit;
 sbit LCD_D5 at RD5_bit;
 sbit LCD_D6 at RD6_bit;
 sbit LCD_D7 at RD7_bit;
 sbit LCD_RS_Direction at TRISD1_bit;
 sbit LCD_EN_Direction at TRISD0_bit;
 sbit LCD_D4_Direction at TRISD4_bit;
 sbit LCD_D5_Direction at TRISD5_bit;
 sbit LCD_D6_Direction at TRISD6_bit;
 sbit LCD_D7_Direction at TRISD7_bit;
// End LCD module connection definition

//global variables
char *freq = "0000000.00";
long count, accum;
float frequency;
short ccp1int, tmr1int, i;

void Display_Freq(float freq2write) {
 int a=0;
 a =FloatToStr(freq2write, freq);
 if (a != 0)
    Lcd_Out(1, 1, "unsuccessful    ");
 else {
    Lcd_Cmd(_LCD_CLEAR);             // CLEAR display
    Lcd_Out(1, 1, freq);
    Lcd_Out(2,10, "in Hz");
    }
 }

// Interrupt service routine
void interrupt() {
  if(PIR1.CCP1IF) {
     ccp1int = 1;
     accum = count - CCPR1;
     count = CCPR1;
  }
  if(PIR1.TMR1IF){
   tmr1int ++;
   PIR1.TMR1IF = 0;     //reset timer1 flag
}
}

void main() {
 ADCON1 = 0x06;         //All I/O pins are configured as digital
 TRISC =  0xFF;
 // TMR1 settings
 T1CON.TMR1CS = 0;          // timer mode  Fosc/4
 PIE1.TMR1IE = 1;           //enable TMR1 inturrupt
 T1CON.T1CKPS0 = 1;          //prescaler  1:4
 T1CON.T1CKPS1 = 1;
 //CCP1 setting
 PIE1.CCP1IE = 0;           //disable ccp1 inturrupt
 CCP1CON = 0x05;            //CCP1 every fourth rising edge
 PIR1.CCP1IF = 0;           //avoid posible fals inturrupt
 PIE1.CCP1IE = 1;           //enable ccp1 inturrupt
 INTCON.PEIE = 1;           //enable all low priority peripheral interrupts
 INTCON.GIE = 1;            //Enable Global Inturrupt
 
 Lcd_Init();
 Lcd_Cmd(_LCD_CLEAR);             // CLEAR display
 Lcd_Cmd(_LCD_CURSOR_OFF);        // Cursor off
 Lcd_Out(1,1,"Freq conversion");
 delay_ms(5000);
 
 for(;;)
 {
  T1CON.TMR1ON = 1;                //start timer1
  for(i = 0; i < 2; i++)                 //to catch two consecutive ccp1 interrupts 
  {
  do{}while(!ccp1int);
  ccp1int = 0;                          //reset ccp1 flag indicator
  }
  T1CON.TMR1ON = 0;                      //stop timer1
  accum = tmr1int*65356 + accum;
  frequency = (Get_Fosc_kHz())/accum;
  Display_Freq(frequency);
  count = 0;        //reset count
  tmr1int = 0;     //reset timer1 flag indicator
  accum = 0;      //reset accumulator 
  }
}

[moved from analog design section]
 

HI
i did not go through your code thoroughly but with a quick glance I see that you are not clearing PIR1.CCP1IF flag in your ISR.
 

I have modified the code like you said, clearing the CCP inturrupt, and also made some changes, but still with no luck

Code:
// Define LCD module connections.
 sbit LCD_RS at RD1_bit;
 sbit LCD_EN at RD0_bit;
 sbit LCD_D4 at RD4_bit;
 sbit LCD_D5 at RD5_bit;
 sbit LCD_D6 at RD6_bit;
 sbit LCD_D7 at RD7_bit;
 sbit LCD_RS_Direction at TRISD1_bit;
 sbit LCD_EN_Direction at TRISD0_bit;
 sbit LCD_D4_Direction at TRISD4_bit;
 sbit LCD_D5_Direction at TRISD5_bit;
 sbit LCD_D6_Direction at TRISD6_bit;
 sbit LCD_D7_Direction at TRISD7_bit;
// End LCD module connection definition

//global variables
char *freq = "0000000.00";
long accum=0;
float frequency=0.0;
float clk=Get_Fosc_kHz();
short tmr1int=0;
short ON;

void Display_Freq(long counted) {
 if(counted!=0)
    frequency = clk/counted;
 else
    frequency = 0;
 FloatToStr(frequency, freq);
 Lcd_Out(2, 6, freq);
 Lcd_Out(2,15, "kHz");
 tmr1int = 0;     //reset timer1 flag indicator
 delay_ms(100);

 }

// Interrupt service routine

void inturrupt_tmr1() {
  if(PIR1.TMR1IF){
   tmr1int ++;
   PIR1.TMR1IF = 0;     //reset timer1 flag
}
}

void interrupt_ccp() {
  if(PIR1.CCP1IF) {
     PIR1.CCP1IF =0;
     if(!ON) {
      TMR1H = 0x00;
      TMR1L = 0x00;
      ON = 1;}
     else {
      accum =(CCPR1H <<8) | CCPR1L ;
      ON = 0;
      }
  }
}

void main() {
 ADCON1 = 0x06;         //All I/O pins are configured as digital
 TRISC =  0xFF;
 TRISD = 0x00;
 // TMR1 settings
 T1CON.TMR1CS = 0;          // timer mode  Fosc/4
 PIE1.TMR1IE = 1;           //enable TMR1 inturrupt
 T1CON.T1CKPS0 = 1;          //prescaler  1:4
 T1CON.T1CKPS1 = 1;
 //CCP1 setting
 PIE1.CCP1IE = 0;           //disable ccp1 inturrupt
 CCP1CON = 0x05;            //CCP1 every fourth rising edge
 PIR1.CCP1IF = 0;           //avoid posible fals inturrupt
 INTCON.PEIE = 1;           //enable all low priority peripheral interrupts
 INTCON.GIE = 1;            //Enable Global Inturrupt

 Lcd_Init();
 Lcd_Cmd(_LCD_CLEAR);             // CLEAR display
 Lcd_Cmd(_LCD_CURSOR_OFF);        // Cursor off
 Lcd_Out(1,1,"Freq conversion");
 Lcd_Out(2,1,"Freq=");
 
 PIE1.CCP1IE = 1;           //enable ccp1 inturrupt
 T1CON.TMR1ON = 1;                //start timer1
 while(1){
 Display_Freq(accum);}
}
 

Did you try running it in some simulator?
That will give you a better idea about if anything is wrong. May be you should try it using mpsim first. Doing that you can have access to individual registers. So your debugging will be much easier
 

Did you try running it in some simulator?
That will give you a better idea about if anything is wrong. May be you should try it using mpsim first. Doing that you can have access to individual registers. So your debugging will be much easier

i hv tried with proteus, and also with mikroc's own debugger tool, and output frequency is always =0.
 

Zip and post your mikroC project files and Proteus file. I will try to fix it.

This is wrong. accum =(CCPR1H <<8) | CCPR1L ;

accum = CCPR1H;
accum = accum << 8 | CCPR1L;

accum can be unsigned int instead of long.

Edit: Where is this function defined? Get_Fosc_kHz(); Is it a library function?
 
Last edited:

and during your debugging, did u happen to check if your program counter is getting into all the functions and register values are getting updates??
I dont think proteus is a good idea for debugging internal working of controller.
 

Dear jayanth.devarayanadurga,
I have attached the code and proteus files here. thanks for your time.

Dear shatruddha,
when i check with Proteus, it seems, the interrupt isr is never initiated. but i dont know what i am doing wrong.
 

Attachments

  • freq_meter.rar
    19 KB · Views: 80

its built-in function under the "_Lib_Delays.c" [Mikroc V.6.0.0]

the excerpt for Get_Fosc_kHz() code is:

unsigned long Get_Fosc_kHz(){

return Clock_kHz();

}

i have tried using a constant in place of the 'clk =Get_Fosc_kHz(); but gave me no difference.
 

Attachments

  • _Lib_Delays.c.txt
    2 KB · Views: 110

ow yes, sorry, i jst did. [almost 4am here forgive my overlooking]

i get a frequency reading, its great but not very accurate. fr f = 800Hz i get 7.096e-1 KHz; for 3kHz, output = 2.75, for 11.2k output = 11.57k. for higher frequencies its good i guess..
can u pls share the code, or what mistake i hv done on my previous code
 

I just pul some fixed value for clk. Actually Get_Fosc_KHz() is returning 0. So, value remains 0 all the time. For example make clk = 1000000 and thensee whay value you get for a certain frequency. Then use a calibrating factor to get the exact frequency. Once I fix the code I will post it.
 
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top