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.

Calculating waveform frequency with a PIC

Status
Not open for further replies.

Sodrohu

New Member
Hello again! Right now I'm trying to finish a project where I'm supposed to measure the frequency of a square oscillating 5V waveform from. I'm using a PIC16F628A for now, but since I'm measuring a digital value any other PIC should work. Here's the code:

Code:
/*
*/

#include <htc.h>
#include "usart.h"
__CONFIG(HS & WDTDIS & PWRTEN & BORDIS  & LVPDIS & MCLREN );

#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>

#ifndef _XTAL_FREQ
 // Unless specified elsewhere, 4MHz system frequency is assumed
 #define _XTAL_FREQ 20000000
#endif

//definitions
#define INPUT 	RB0
#define START 	RB3
#define LEDOUT	RB4

int count = 0;
bool isrun = false;
bool isstart = false;

//	function prototype		(every function must have a function prototype)
//==========================================================================
void init_timers(void);
void init_all(void);

//EEPROM init and variables
__EEPROM_DATA(0, 1, 2, 3, 4, 5, 6, 7); 


void main() 
{
	unsigned char input;
	init_all();
	init_timers();
	init_comms();	// set up the USART - settings defined in usart.h

	// Output a message to prompt the user for a keypress	
	printf("\rPress the START button to start the program\n");
	
	while(1)
	{	
		while(!START)
		{}
		isstart = true;
		__delay_ms(500);
		__delay_ms(500);
		
		//input = count;
		//input = getch();	// read a response from the user
			//LEDOUT = ~LEDOUT;
		
		isstart = false;
		printf("\rFrequency of Waveform: %i ",count-1);	// echo it back
		count = 0;
	}
	
		
}

void init_all(void) // initialise all values and variables
{
	TRISA = 0b00000111;
	PORTA = 0xFF;
	TRISB = 0b00001101; 	// port B as output
	PORTB = 0xFF; 			//clear portB
	//ADCON1 = 0x06; 			//sets the PORTA to be all digital I/Os
}

void interrupt ISR() //interrupt for TMR0 and TMR1
{
	if (T0IF) //if TM0 interrupt triggered
	{	if(isstart)
		{
//			if((!INPUT) && (isrun))
//			{	count++;
//				isrun = false;
//				LEDOUT = 0;
//			}
//			if((INPUT) && (!isrun))
//			{
//				isrun = true;
//				LEDOUT = 1;
//			}
		}
		//LEDOUT = ~LEDOUT;
		TMR0 = 131;
		T0IF = 0; //sets the TMR0 interrupt to start again
	}
	if (TMR1IF) //if TM1 interrupt triggered
	TMR1IF = 0; //sets the TMR1 interrupt to start again
	
	if(OERR)
	{
		CREN=0;
		CREN=1;
	}
	if(FERR)
	{
		RCREG = RCREG;
		RCREG = RCREG;
		RCREG = RCREG;
	}
	if(INTF) 
	{	
		if(isstart) 
		{
			count++;
		}
		INTF = 0;			// clear the interrupt
	}
}


void init_timers(void)
{
//TMR 0 initialise
PS0 = 1;
PS1 = 0;
PS2 = 0; 		//001 prescaler 1:4
PSA = 0;		//assign prescaler to timer0
T0CS = 0;		//CLK0 as internal cycle clock
T0IE = 1;		//enable timer 0
INTEDG = 1;	// falling edge trigger the interrupt
RBPU = 0;		// Use internal pullups
INTE = 1;		// enable the external interrupt
PEIE = 1;		//
GIE = 1;		//enable global interrupt
TMR0 = 131;

//TMR1 initialise
T1CKPS0 = 1; //prescaler as 8
T1CKPS1 = 1;
TMR1CS= 0;
T1OSCEN = 0;
TMR1IE = 1;
TMR1L = 0x00;
TMR1H = 0x00;
}

The code works to an extent. What I did is that after the button is pushed, in a duration of 1 sec, whenever the input pin RB0 detects a high, the interrupt is triggered and count is incremented by 1. Using Proteus simulation, I got results that are error-prone: if 100 Hz is used, actual result is 111 Hz (10% error). The error increases as frequency value increases.

I know I'm not fully considering other aspects of the input waveform(if a 0 comes in first, should I track both high and low values instead of just high vales...), but I'm thinking them up. Does anyone of you has better ways to implement thins?
 
Why not use the capture module to time the pulse width of the square wave, then convert the pulse width to frequency?
 
In capture mode, it can be configured to start timer 1 on the rising edge of a square wave pulse. Once the falling edge of the square wave pulse is detected, it then "captures" the value in timer 1 and places this value in registers CCPR1L and CCPR1H. From there you can read the captured timer value and calculate the frequency from that.
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top