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:
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?
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?