# 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.

#### Pommie

##### Well-Known Member
Most Helpful Member
You can use the ccp (capture, compare) module to do this in hardware.

Mike.

#### Ian Rogers

##### User Extraordinaire
Forum Supporter
Most Helpful Member
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!

#### Pommie

##### Well-Known Member
Most Helpful Member
Not on that chip.... It has less peripherals than the original pic16f84.. Hardly any memory!
Wow, just looked at the datasheet. A very simple chip indeed.

Mike.

#### Pommie

##### Well-Known Member
Most Helpful Member
To the OP, what kind of signals do you need to detect?

Mike.

#### Fabianr18

##### New Member
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

#### Ian Rogers

##### User Extraordinaire
Forum Supporter
Most Helpful Member
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..

#### jpanhalt

##### Well-Known Member
Most Helpful Member
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.

#### Fabianr18

##### New Member
thanks for the advice I'm starting to understand more and more

#### jpanhalt

##### Well-Known Member
Most Helpful Member
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.

#### Pommie

##### Well-Known Member
Most Helpful Member
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.

#### Ian Rogers

##### User Extraordinaire
Forum Supporter
Most Helpful Member
Pommie! Trouble here is, he will be writing to an LCD and will need a bit 'o' maths.. The OP being new to all this its going to be tricky!! Waiting for a pin may not work here..

#### Pommie

##### Well-Known Member
Most Helpful Member
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.

#### Fabianr18

##### New Member
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:

#### Pommie

##### Well-Known Member
Most Helpful Member
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:

#### Fabianr18

##### New Member
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
399.2 KB · Views: 83

#### Pommie

##### Well-Known Member
Most Helpful Member
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:

#### jpanhalt

##### Well-Known Member
Most Helpful Member
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:

#### Ian Rogers

##### User Extraordinaire
Forum Supporter
Most Helpful Member
You may well be doing this exercise to see "If you can" But reading 4 switches down one wire would be a whole lot easier using the built in ADC.. Then only one micro is needed..

#### Daniel Wood

##### Member
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.

Replies
1
Views
3K
Replies
12
Views
1K
Replies
6
Views
3K
Replies
8
Views
2K
Replies
1
Views
6K