Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

square wave pulse detector using PIC16F676

Status
Not open for further replies.

Fabianr18

New Member
Now that I gained a bit more experience writing C language a task of mine is to write a program to detect different pulses and represent them with a LEDS. anyone have any suggestions on how to do this. I have done some research and i came to the conclusion of using Timer0 operation to compare it with the internal freq of 4Mhz.
 
You can use the ccp (capture, compare) module to do this in hardware.

Mike.
 
You can use the ccp (capture, compare) module to do this in hardware.

Mike.
Not on that chip.... It has less peripherals than the original pic16f84.. Hardly any memory!
 
i have to detect different times of a square wave and out put them using an LED (simple if else statement) for example if the input pulse is 200us i should output 0000 or 300us output 0001

only thing i dont know, is how to implement is the detection of the pulse by using the timer1 or timer0 or maybe theirs an easier way to do this
 
If your square wave enters by the int pin...
C:
void interrupt ISR(void)
   {
   if( INTEDG == rising )
      {
      TMR0=0;
      INTEDG = falling;   
      }
   else 
      {
      pulse_time = TMRO;
      INTEDGE = rising;
      }
   INTF = 0;
   }

THIS ISN'T TESTED... Just the idea... You may be better with timer1 as timer0 is an 8 bit and will not do long pulses..
 
As already mentioned, that is a very limited chip. Perhaps that was assigned on purpose.

Here is one approach: INT on RA2 is edge triggered. Use it for your signal.

Assuming the pulse idles low, set INT to a rising edge. In the interrupt, read TMR1H:L registers and start TMR1 (TICON,0 =1). Then switch to falling edge for the next interrupt and stop TMT1 (TICON,0 =0). Read your TMR1H:L registers and subtract to find out how long the pulse was.

As mentioned, if you have capture, it is easier, but for the precision you need, starting and stopping TMR1 is easy to visualize.

TMR1 has various pre-scale values, so regardless of your clock speed (within reason) you can get a count to equal microseconds or something else. If the counter rolls over just once during the measurement, that won't affect results, if your subtraction is done correctly.
 
Just one added note. Once you get it to work starting and stopping TMR1, try it without that complication. It will work, but you cannot have more than 1 rollover in each timing period. That's basically what I do.
 
I note that the chip suggested has a gate input on timer1. Therefore, if you connect your signal to both the T1G and INT pins (RA4 & RA2) with an interrupt on falling edge only, the timer can be read and reset in that interrupt and it will contain the length of the pulse. Another way is to just connect to RA4 and use the IOC (interrupt on change) to generate the interrupt.

BTW, you don't have to use interrupts, you can simply wait for RA4 to go low and then read and reset the timer.
I.E. - untested
Code:
    while(1){
        while(RA4);        //wait for signal to go low
        length = TMR1;
        TMR1=0;
        //do whatever with length
        if(length<2000){
            //length was less than 2000 clock cycles
        }else if(length<4000){
            //between 2000 and 4000
        }else{
            //over 4000
        }
    }
Edit, to use this method you must setup timer1 to use the gate signal.

Mike.
 
The OP said LEDs so I assume it's something like an RC servo signal and the LED should light when the pulse is over a certain length.

Mike.
 
so i wrote down a code based on a tutorial and changed all f the parameters to work with my problem "reverse engineering " but it doesn't seem to do anything

C:
#include <xc.h>
#pragma config FOSC = INTRCIO// Oscillator Selection bits (INTOSC oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF // RA3/MCLR pin function select
#pragma config BOREN = OFF // Brown-out Detect Enable bit (BOD disabled)
#pragma config FOSC = INTRCIO
#pragma config CP = OFF // Code Protection bit (protection disabled)
#pragma config CPD = OFF // Data Code Protection bit (protection disabled)
#define _XTAL_FREQ 4000000 // 4MHz


#define PulseLimit 30000

volatile unsigned int PulseValue;
struct
{
    volatile unsigned PulseFound :1;
}flags;

void interrupt TImer1_GateISR()
{
    PulseValue =TMR1;
    flags.PulseFound =1;
    TMR1 =0;
    PIR1bits.TMR1IF =0;
    T1CONbits.TMR1CS =1;
}
main ()
{
    unsigned int Timer1Count;
    OSCCAL =0b11111100;
    ANSEL=0b000000;
    ADCON0bits.ADON=0;
    TRISA=0b00010000;
    TRISC=0b00000000;
T1CON=0b01000011;
    TMR1=0;
    PIR1bits.TMR1IF=0;
    INTCONbits.PEIE=1;
    INTCONbits.GIE=1;
    PIE1bits.TMR1IE=1;
    T1CONbits.TMR1ON=1;
  
    flags.PulseFound=0;
    PulseValue =0;
  
    while(1){
        if(flags.PulseFound ==1)
        {
            di();
            Timer1Count = PulseValue;
            ei();
            if(Timer1Count > PulseLimit){
            PORTC=0b00000000;
        }
            else if(Timer1Count < PulseLimit){
            PORTC =0b00000000;
            }
         flags.PulseFound=0;
            }
          
        }
  
}
 
Last edited by a moderator:
Your code is interrupting on timer1 overflow.

What I would try first is to simply watch and count.
I.E.
Code:
main ()
{
    ANSEL=0b000000;
    ADCON0bits.ADON=0;
    TRISA=0b00010000;
    TRISC=0b00000000;
    T1CON=0b00000000;
 
    while(1){
        unsigned int Timer1Count;
        TMR1=0;             //clear timer
        while(!RA4);        //wait for high
        T1CONbits.TMR1ON=1; //start timer
        while(RA4);         //wait low
        T1CONbits.TMR1ON=0; //stop timer
        Timer1Count=TMR1;   //copy timer
        // use the timer value here to light LEDs etc.
    }
}

The above, untested, code should get the length of the pulse within a few clock cycles.
Note, no interrupts to complicate things.

Edit, my earlier suggestion of using the timer1 gate function won't work as the gate is active low. You also haven't told us the length of pulses expected or how often to expect them. For example a radio control receiver puts out a 1 to 2mS pulse every 20mS.

Mike.
 
Last edited:
the length of each pulse is in micro seconds and the waves wont stop coming in and the length of that waves will change manually by another micro controller the block diagram of the project is posted below,
 

Attachments

  • pic.jpg
    pic.jpg
    399.2 KB · Views: 334
If your pulses are between 200 and 250 μS and you have 4 different lengths, that's only around 16 clock cycles difference per pulse. I would, at the very least, increase your oscillator frequency to something like 20MHz so you have a better chance of getting this to work. At 20MHz you will have about 80 cycles different in timer readings.

If the pulse lengths are very accurate and you don't have stray capacitance then the above code should still work.

Note, to use interrupts will increase your overhead immensely - to execute an empty interrupt can take over 20 cycles just for entry and context saving.

BTW, in your code above you appear to be testing for a pulse of 30,000 μS (30mS). If you have control over how long the pulses can be then I would suggest 1 to 4mS with a gap of a couple of mS.

Actually, I may have misread your diagram. Are the pulses 200, 250, 300 & 350μS? If so and you have a suitable gap between them then the above should work fine.

Edit, misread your diagram again. Do you have 16 different pulse lengths? Is 200μS equal to zero?

Mike.
 
Last edited:
Pommie

Your last assumption seems correct. See the attachment here: https://www.electro-tech-online.com/threads/pwm-pic16f676.152459/#post-1310770

200 us =0 ; then count by 50 us units so 250 us =1, 300 us =2 and so forth.

Edit: Darn it. Just lost a long edit -- guess auto save doesn't work on an edit.

Unfortunately, I used "interrupt" a bit loosely in my comment above -- probably because that is what I was working on at the time. What I should have said was you can use an interrupt or just monitor the appropriate flag/state change and then read TMR1. One way to read it with your chip is to start and stop the timer as in Pommie's code. That introduces some error which can be corrected by careful timing. The other method is to let TMR1 run and read it on the fly.

The usual way to do that is to read the high byte (TMR1H) first, then the low byte, then check to see if TMR1L rolled over by checking for a change in the high byte. I used to have a nice article on that method in Assembly, but cannot find it right now. I did find a description of that method in text, and at risk of looking foolish, here it is.

Source: https://www.picbasic.co.uk/forum/showthread.php?t=4092
Code:
X var BYTE ' in addition to your variables

period.highbyte = TMR1H
period.lowbyte = TMR1L
X = TMR1H – period.highbyte
If X = 0 then Continue
period.highbyte = TMR1H
period.lowbyte = TMR1L
Continue:
John

Edit#2: Corrected "TMR1" to TMR1L -- hope it was clear by context that I was referring to the low byte.
 
Last edited:
Without a CCP module, it would be rather difficult. One way may be to integrate the signal and peak detect with the analogue pin?
No doubt i'd get shot down for this suggestion as it would only work well in a very limited pulse timing window. It could work if your pulses are between 200-300uS
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top