Hot!(solved)Frequency Counter Using PIC18F4550

Author
BAGHEDOUD
New Member
  • Total Posts : 10
  • Reward points : 0
  • Joined: 2018/05/11 04:02:17
  • Location: 0
  • Status: offline
2018/05/15 04:38:51 (permalink)
0

(solved)Frequency Counter Using PIC18F4550

Hi everyone,
 
I'm kinda ne to PIC programming so I'm trying to make a frequency Counter with PIC18F45550, the problem is when i start the simulation on proteus i got only 200K Hz as the highest Frequency that I can read correctely. here is my Code on MikroC, I'm using 8Mhz Crys, 
 
Thank you,
 
//////////////////////////////////////////////////////////////////////////
// LCD module connections
sbit LCD_RS at RD2_bit;
sbit LCD_EN at RD3_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 TRISD2_bit;
sbit LCD_EN_Direction at TRISD3_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 connections
 
 
unsigned int Freq;
unsigned char Freq_Display[]="4294960000007295",txt[]="000";
char flag;
unsigned int Cw=0;

void interrupt(){
if(PIR1.CCP1IF==1){
PIR1.CCP1IF=0;
Cw=Cw+1;
PORTE.RE0=~PORTE.RE0;
}
else PORTE.RE0=0;
}
void main(){
Lcd_Init();
Lcd_Cmd(_LCD_CURSOR_OFF);
ADCON1=0x07;
CMCON=0x07;
TRISA=0x00;
PORTA = 0;
PORTB = 0;
PORTC = 0;
PORTD = 0;
TRISC = 0b00000100;
TRISD = 0b00000000;
T1CON = 0b00110001;
CCP1CON = 0b00000101;
INTCON = 0b11000000;
PIE1.CCP1IE=1;
TRISE=0;
while(1){
LongToStr(Cw,Freq_Display);
Lcd_Out(1,1,Freq_Display);
}
}
post edited by BAGHEDOUD - 2018/06/03 08:53:06
#1

16 Replies Related Threads

    jack@kksound
    code tags!
    • Total Posts : 2859
    • Reward points : 0
    • Joined: 2014/05/14 10:03:19
    • Location: 0
    • Status: online
    Re: Frequency Counter Using PIC18F4550 2018/05/15 11:14:58 (permalink)
    +2 (2)
    From your program code:
    You are using the CCP1 module to detect the rising edge of your signal to measure, this causes an interrupt.
    In the ISR you increment your Cw counter.
    Your CCP1 module is using timer1 as the timer source and timer1 counts the Fosc/4 signal (8Mhz/4 = 2Mhz) with a prescaler setting of 8:1 so your timer1 increments at (2Mhz/8 = 250 Khz).
    Because the CCP1 is interrupting on the rising edge of your input signal I fail to see how you get a frequency by simply incrementing the Cw var. And your setting of the timer1 prescaler seemsunused. Also you are not using the values captured from timer1 by the CCP1 module (on every interrupt). And you never reset the value of Cw, it simply increments forever.
    Is this your actual code?
     
    #2
    BAGHEDOUD
    New Member
    • Total Posts : 10
    • Reward points : 0
    • Joined: 2018/05/11 04:02:17
    • Location: 0
    • Status: offline
    Re: Frequency Counter Using PIC18F4550 2018/05/16 08:00:57 (permalink)
    0
    Hi 

     
    Thank you for your reply, you are right the code is incomplete, because i wanna just the counter that can count more than 200K in one second, and i guess you make it clear for me now , thank you, the other part of my code is that i ue Timer0 as a timer to count 1Sec then i get the coutned value by timer1 and then i got the frequency of my signal, here is the full Code :
    /////////////////////////////////////////////
    // LCD module connections
    sbit LCD_RS at RD2_bit;
    sbit LCD_EN at RD3_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 TRISD2_bit;
    sbit LCD_EN_Direction at TRISD3_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 connections
     
     
    unsigned int Freq;
    unsigned char Freq_Display[]="4294960000007295",txt[]="000";
    char flag;
    unsigned int Time;
    unsigned int Cw=0;

    void interrupt(){
    if(INTCON.TMR0IF){
    INTCON.TMR0IF=0;
    if(Time==1000){
    Time=0;
    flag=1;
    INTCON.INT0IE=0;
    }
    else{
    Time++;
    TMR0L=0x17;
    TMR0H=0xFC;
    T0CON.TMR0ON=1;

    }
    if(PIR1.CCP1IF==1){
    PIR1.CCP1IF=0;
    Cw=Cw+1;
    }
    } }
    void main(){
    Lcd_Init();
    Lcd_Cmd(_LCD_CURSOR_OFF);
    ADCON1=0x07;
    CMCON=0x07;
    TRISA=0x00;
    PORTA = 0;
    PORTB = 0;
    PORTC = 0;
    PORTD = 0;
    TRISC = 0b00000100;
    TRISD = 0b00000000;
    T1CON = 0b00110001;
    CCP1CON = 0b00000101;
    INTCON = 0b11000000;
    PIE1.CCP1IE=1;
    INTCON.TMR0IE=1; //enable Timer0
    INTCON.TMR0IF=0; //get timer0's floag low
    TMR1L=0;
    TMR1H=0;
    PIR1.CCP1IF=0; //get capture mode's flag low
    PIR1.TMR1IF=0; //get timer1 flag low
    INTCON.GIE=1; //enable global interrupts
    INTCON.INT0IE=1; //enable external interupts interrupts
    IPR1.CCP1IP=0; //give low priority to CCP that counts egdes
    INTCON2.TMR0IP=1; //give high priority to Timer0 to count one second for frequency

    while(1){
    if(flag){
    flag=0;
    LongToStr(Cw,Freq_Display);
    Lcd_Out(1,1,Freq_Display);
    Cw=0;
    }
     
    }}
    #3
    jack@kksound
    code tags!
    • Total Posts : 2859
    • Reward points : 0
    • Joined: 2014/05/14 10:03:19
    • Location: 0
    • Status: online
    Re: Frequency Counter Using PIC18F4550 2018/05/16 10:55:45 (permalink)
    +1 (1)
    To use interrupt priorities you must set the IPEN bit in the RCON register. Also you will then need two ISR functions, one for low and one for high priority.
    #4
    BAGHEDOUD
    New Member
    • Total Posts : 10
    • Reward points : 0
    • Joined: 2018/05/11 04:02:17
    • Location: 0
    • Status: offline
    Re: Frequency Counter Using PIC18F4550 2018/05/17 03:34:03 (permalink)
    0
    Hi, thanks for your reply, so what i can understand now is that the pic cant count more than 12Mhz as maximum, with a 48Mhz crystal, plus when i made 2 functions low and high in interrupt, i got no interrupt at all , even the counts that i was getting before is no more interrupting.
     
     
    /////////////////////////////////////////////////////////////////
    sbit LCD_RS at RD2_bit;
    sbit LCD_EN at RD3_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 TRISD2_bit;
    sbit LCD_EN_Direction at TRISD3_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 connections
     
    unsigned char Freq_Display[]="0123456789ABCDEF";
    char flag;
    unsigned int Time;
    unsigned int Freq=0;
    void interrupt_high(){
    if(INTCON.TMR0IF){
    INTCON.TMR0IF=0;
    if(Time==1000){
    Time=0;
    flag=1;
    INTCON.INT0IE=0;
    }
    else{
    Time++;
    TMR0L=0x17;
    TMR0H=0xFC;
    T0CON.TMR0ON=1;
    }
    }
    }
    void interrupt_low(){
    if(PIR1.CCP1IF==1){
    PIR1.CCP1IF=0;
    Freq=Freq+1;
    }
    }
     

    void main(){
    Lcd_Init();
    Lcd_Cmd(_LCD_CURSOR_OFF);
    RCON.IPEN=1;
    ADCON1=0x07;
    CMCON=0x07;
    TRISC = 0b00000100;
    T1CON = 0b00110001;
    CCP1CON = 0b00000101;
    INTCON = 0b11000000;
    PIE1.CCP1IE=1;
    INTCON.TMR0IE=1; //enable Timer0
    INTCON.TMR0IF=0; //get timer0's floag low
    PIR1.CCP1IF=0; //get capture mode's flag low
    PIR1.TMR1IF=0; //get timer1 flag low
    INTCON.GIE=1; //enable global interrupts
    INTCON.INT0IE=1; //enable external interupts interrupts
    IPR1.CCP1IP=0; //give low priority to CCP that counts egdes
    INTCON2.TMR0IP=1; //give high priority to Timer0 to count one second for frequency
    Lcd_Out(1,1,"Frequence:");
    Lcd_Out(2,15,"Hz");
    while(1){
    if(flag){
    flag=0;
    IntToStr(Freq,Freq_Display);
    Lcd_Out(2,1,Freq_Display);
    Freq=0;
    }
    }
    }
    #5
    jack@kksound
    code tags!
    • Total Posts : 2859
    • Reward points : 0
    • Joined: 2014/05/14 10:03:19
    • Location: 0
    • Status: online
    Re: Frequency Counter Using PIC18F4550 2018/05/18 09:19:21 (permalink)
    +1 (1)
    Two things (at least):
    When using priority interrupts (as you are) this:
    INTCON.GIE=1; //enable global interrupts

    is more correctly written as:
    INTCON.GIEH=1; // enable HIGH priority interrupts

    and you must add:
    INTCON.GIEL=1;//enable LOW priority interrupts

    Also ALLWAYS completely set-up ALL aspects of the interrupts before you set the global enables, you are not doing that in your code.
    #6
    BAGHEDOUD
    New Member
    • Total Posts : 10
    • Reward points : 0
    • Joined: 2018/05/11 04:02:17
    • Location: 0
    • Status: offline
    Re: Frequency Counter Using PIC18F4550 2018/05/19 16:02:30 (permalink)
    0
    Hi thank you for your reply, sorry but i didnt get the  last thing u said, because i did everything but it didnt work somehow, 
     
    //////////////////////////////////////////////////////
    sbit LCD_RS at RD2_bit;
    sbit LCD_EN at RD3_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 TRISD2_bit;
    sbit LCD_EN_Direction at TRISD3_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 connections
    unsigned char Freq_Display[]="0123456789ABCDEF";
    char flag;
    unsigned int Time;
    unsigned int Freq=0;
    void interrupt_high(){
    if(INTCON.TMR0IF){
    INTCON.TMR0IF=0;
    if(Time==1000){
    Time=0;
    flag=1;
    INTCON.INT0IE=0;
    }
    else{
    Time++;
    TMR0L=0x17;
    TMR0H=0xFC;
    T0CON.TMR0ON=1;
    }
    }
    }
    void interrupt_low(){
    if(PIR1.CCP1IF==1){
    PIR1.CCP1IF=0;
    Freq=Freq+1;
    }
    }

    void main(){
    Lcd_Init();
    Lcd_Cmd(_LCD_CURSOR_OFF);
    RCON.IPEN=1;
    ADCON1=0x07;
    CMCON=0x07;
    TRISC = 0b00000100;
    T1CON = 0b00110001;
    CCP1CON = 0b00000101;
    INTCON = 0b11110000;
    PIE1.CCP1IE=1;
    INTCON.TMR0IE=1; //enable Timer0
    INTCON.TMR0IF=0; //get timer0's floag low
    PIR1.CCP1IF=0; //get capture mode's flag low
    PIR1.TMR1IF=0; //get timer1 flag low
    INTCON.INT0IE=1; //enable external interupts interrupts
    IPR1.CCP1IP=0; //give low priority to CCP that counts egdes
    INTCON2.TMR0IP=1; //give high priority to Timer0 to count one second for frequency
    Lcd_Out(1,1,"Frequence:");
    Lcd_Out(2,15,"Hz");
    INTCON.GIEH=1; //enable global interrupts
    INTCON.GIEL=1; //enable global interrupts
    while(1){
    if(flag){
    flag=0;
    IntToStr(Freq,Freq_Display);
    Lcd_Out(2,1,Freq_Display);
    Freq=0;
    }
    }
    }
    /////////////////////////////////////
     
    here is what i got in proteus :
     

    Attached Image(s)

    #7
    NorthGuy
    Super Member
    • Total Posts : 5081
    • Reward points : 0
    • Joined: 2014/02/23 14:23:23
    • Location: Northern Canada
    • Status: offline
    Re: Frequency Counter Using PIC18F4550 2018/05/19 20:48:38 (permalink)
    +1 (1)
    If you want to count higher frequencies, do not use CCP. Instead, use a timer connected to an external pin (where the frequency to be counted comes in). Read the timer at regular intervals. Say, if you read 1000 times a second, the difference between consecutive counts will give you frequency in kHz.
     
    You can use pre-scaler on the counting timer. With pre-scaler, most PICs can go up to 50MHz (don't know about yours, it's too old, see the datasheet).
     
    #8
    1and0
    Access is Denied
    • Total Posts : 8482
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Frequency Counter Using PIC18F4550 2018/05/19 21:39:27 (permalink)
    +2 (2)
    NorthGuy
    You can use pre-scaler on the counting timer. With pre-scaler, most PICs can go up to 50MHz (don't know about yours, it's too old, see the datasheet).

    Timer0 on most, if not all, 8-bit PIC devices can read up to 50 MHz with the prescaler.
    #9
    BAGHEDOUD
    New Member
    • Total Posts : 10
    • Reward points : 0
    • Joined: 2018/05/11 04:02:17
    • Location: 0
    • Status: offline
    Re: Frequency Counter Using PIC18F4550 2018/05/20 06:27:52 (permalink)
    +1 (1)
    thank you for your replies, i'll try this solution for now , because i want to counter a frequency up to 35Mhz or 40Mhz. 
    #10
    BAGHEDOUD
    New Member
    • Total Posts : 10
    • Reward points : 0
    • Joined: 2018/05/11 04:02:17
    • Location: 0
    • Status: offline
    Re: Frequency Counter Using PIC18F4550 2018/05/28 02:44:10 (permalink)
    0
    I've been trying to figure out the idea you said those past days, but unfortunately I could really understand the idea, so I would like to ask you about more explications, or an example for this method. Thanks so much !!!
    #11
    BAGHEDOUD
    New Member
    • Total Posts : 10
    • Reward points : 0
    • Joined: 2018/05/11 04:02:17
    • Location: 0
    • Status: offline
    Re: Frequency Counter Using PIC18F4550 2018/06/01 05:28:29 (permalink)
    0
    Hi , thank you for your replies, i figured out the solution, i just have a little problem here, in my code i can read the frequency up to 131K Hz, and I know exactly the problem is with The Numb variable that doesn't increment correctly, I don't know why , so if anyone can help please.
    /////////////////////////////////////////////////////////////////////////
    void InitTimer1(void);
    sbit LCD_RS at RD4_bit;
    sbit LCD_EN at RD5_bit;
    sbit LCD_D4 at RD0_bit;
    sbit LCD_D5 at RD1_bit;
    sbit LCD_D6 at RD2_bit;
    sbit LCD_D7 at RD3_bit;
    sbit LCD_RS_Direction at TRISD4_bit;
    sbit LCD_EN_Direction at TRISD5_bit;
    sbit LCD_D4_Direction at TRISD0_bit;
    sbit LCD_D5_Direction at TRISD1_bit;
    sbit LCD_D6_Direction at TRISD2_bit;
    sbit LCD_D7_Direction at TRISD3_bit;
     
     
    unsigned int val=0;
    float Timer_Value=0;
    float Frequency=0;
    unsigned int Numb=0;
    char txt[14];
     
     
    void interrupt(){
    if (TMR1IF_bit){
    TMR1IF_bit = 0;
    TMR1H = 0x0B;
    TMR1L = 0xDC;
    val++;
    if(val==4){
    Numb=0;
    }
    }
    if(TMR0IF_bit){
    Numb++;
    TMR0IF_bit=0;
    }
    }
     
     
    void main (void){
    InitTimer1();
    Lcd_init();
    Lcd_cmd(_LCD_CLEAR);
    Lcd_Cmd(_LCD_CURSOR_OFF);
    TRISE=0;
    ADCON1 = 0x0F;
    CMCON = 0x07;
    INTCON.PEIE=1;
    INTCON.GIE=1;
    T0CON=0xA8;
    TRISA.RA4 = 1; //make RA4/TOCKI an input
    TMR0H = 0;
    TMR0L = 0;
    Lcd_Out(1,1,"Frequency");
    Lcd_Out(2,15,"Hz");
     

    while(1){
    delay_ms(1000);
    Timer_Value=TMR0L;
    Timer_Value=(((TMR0H))<<8)|((TMR0L));
    Frequency=(Timer_Value)+(Numb*65535);
    PORTE.RE0=~PORTE.RE0;
    FloatToStr(Frequency,txt);
    lcd_out(1,1,txt);
    TMR0H=0;
    TMR0L=0;
    Frequency=0;
    Timer_Value=0;
    }
    }
     
     

    void InitTimer1(){
    T1CON = 0x31;
    TMR1IF_bit = 0;
    TMR1H = 0x0B;
    TMR1L = 0xDC;
    TMR1IE_bit = 1;
    INTCON = 0xC0;
    }
    #12
    DarioG
    Allmächtig.
    • Total Posts : 54081
    • Reward points : 0
    • Joined: 2006/02/25 08:58:22
    • Location: Oesterreich
    • Status: offline
    Re: Frequency Counter Using PIC18F4550 2018/06/01 05:38:13 (permalink)
    +1 (1)
    make that variable "volatile".
     
    and also write to LATx register, instead of PORTx

    GENOVA :D :D ! GODO
    #13
    BAGHEDOUD
    New Member
    • Total Posts : 10
    • Reward points : 0
    • Joined: 2018/05/11 04:02:17
    • Location: 0
    • Status: offline
    Re: Frequency Counter Using PIC18F4550 2018/06/01 05:54:37 (permalink)
    0
    I did already, about port it's only to see if one second has passed, I made Numb volatile, and still get only the value above 65536, since I'm using a pic18f4550 with 16-bit Timer0, like if the value in the Port RA4 is 100K Hz, I got 34464 Hz which is 100k-65536.
    #14
    DarioG
    Allmächtig.
    • Total Posts : 54081
    • Reward points : 0
    • Joined: 2006/02/25 08:58:22
    • Location: Oesterreich
    • Status: offline
    Re: Frequency Counter Using PIC18F4550 2018/06/01 06:01:50 (permalink)
    0
    I'd say it's a problem of casting to long:
    try
    Frequency=(Timer_Value)+(Numb*65536L);
    (note the 65536)
     
    or
    make Numb long

    GENOVA :D :D ! GODO
    #15
    1and0
    Access is Denied
    • Total Posts : 8482
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Frequency Counter Using PIC18F4550 2018/06/01 06:50:29 (permalink)
    +1 (1)
    For this
    unsigned int Numb=0;
    Frequency=(Timer_Value)+(Numb*65535);

    (Numb*65535) will overflow as it is evaluated as 16-bit math, because both operands are 16-bit integers.
     
    #16
    BAGHEDOUD
    New Member
    • Total Posts : 10
    • Reward points : 0
    • Joined: 2018/05/11 04:02:17
    • Location: 0
    • Status: offline
    Re: Frequency Counter Using PIC18F4550 2018/06/01 06:57:45 (permalink)
    0
    Thank you for all your repliess, i got it worked finally, as I'm using an 8Mg clock, the max frequency without prescaler i could count is 250K, and it's working fine.  here is the code down here:
     
     
    void InitTimer1(void);
    sbit LCD_RS at RD4_bit;
    sbit LCD_EN at RD5_bit;
    sbit LCD_D4 at RD0_bit;
    sbit LCD_D5 at RD1_bit;
    sbit LCD_D6 at RD2_bit;
    sbit LCD_D7 at RD3_bit;
    sbit LCD_RS_Direction at TRISD4_bit;
    sbit LCD_EN_Direction at TRISD5_bit;
    sbit LCD_D4_Direction at TRISD0_bit;
    sbit LCD_D5_Direction at TRISD1_bit;
    sbit LCD_D6_Direction at TRISD2_bit;
    sbit LCD_D7_Direction at TRISD3_bit;
    unsigned int val=0;
    unsigned int Timer_Value=0;
    unsigned long Frequency=0;
    long Numb=-1;
    char txt[14];
    void interrupt(){
    if (TMR1IF_bit){
    TMR1IF_bit = 0;
    TMR1H = 0x0B;
    TMR1L = 0xDC;
    val++;
    }
    if(TMR0IF_bit){
    Numb++;
    PORTE.RE0=~PORTE.RE0;
    TMR0IF_bit=0;
    }
    }
    void main (void){
    InitTimer1();
    Lcd_init();
    Lcd_cmd(_LCD_CLEAR);
    Lcd_Cmd(_LCD_CURSOR_OFF);
    TRISE=0;
    ADCON1 = 0x0F;
    CMCON = 0x07;
    INTCON.PEIE=1;
    INTCON.GIE=1;
    T0CON=0xA8;
    TRISA.RA4 = 1; //make RA4/TOCKI an input
    TMR0H = 0;
    TMR0L = 0;
    Lcd_Out(1,1,"Frequency");
    Lcd_Out(2,15,"Hz");
    while(1){
    if(val==1){
    val=0;
    Lcd_cmd(_LCD_CLEAR);
    Timer_Value=TMR0L;
    Timer_Value=(((TMR0H))<<8)|((TMR0L));
    Frequency=((long)Timer_Value)+(Numb*65535L);
    longToStr((1.03*Frequency),txt);
    Lcd_Out(2,1,txt);
    TMR0H=0;
    TMR0L=0;
    Frequency=0;
    Timer_Value=0;
    Numb=0;
    }
    }
    }

    void InitTimer1(){
    T1CON = 0x31;
    TMR1IF_bit = 0;
    TMR1H = 0x0B;
    TMR1L = 0xDC;
    TMR1IE_bit = 1;
    INTCON = 0xC0;
    }
    #17
    Jump to:
    © 2018 APG vNext Commercial Version 4.5