//////////////////////////////////////////////////////////////////////
//
// File: Frequency-counter-4MHz-7seg-TMR1.c
//
// Author: rohith t
//
// Description:
//
// Measure frequency using TMR1 up to about 50MHz (depends on PIC chip input).
//
// Displays result on 8 x 7segment display.
//
// Compiler : mikroC, mikroElektronika C compiler
// for Microchip PIC microcontrollers
// Version: 5.0.0.3
//
// Note Testing:
//
// Tested on 16F877A
//
// Note measurement accuracy:
//
// The basic accuracy of the unit is set by the crystal oscillator accuracy.
//
// Requirements:
//
// Xtal clock : 4MHz
// (Use any type but better (smaller) ppm specification = better accuracy).
// (for different xtal frequency - recode frequency measurement part & tune).
//
// Target : 16F877A
//
// Accuracy: uses ONLY the main crystal clock as a reference
// - so the counter accuracy depends on the crystal.
//
// Note : re-tune gate_loop when ever code is added/removed.
//
// Check: By using simulator timer see code in gate.c (gate_loop)
// and here.
//
// Version:
// 1.01 16/Feb/06 - Change compiler to 5.0.0.3
// Changed to using RE0 and RE1 as 4017 controls.
// (Frees up analogue ports for other projects was A0,1).
// - more efficient so need to re-code time critical parts.
// 1.00 - Initial release.
//
//
//////////////////////////////////////////////////////////////////////
#include "bit.h"
#include "delay.h"
#include "gate.h"
#include "bcd.h"
#include "sevensegment.h"
//#include "usart_support.h"
//////////////////////////////////////////////////////////////////////
// Globals
//////////////////////////////////////////////////////////////////////
// globals for time critical code - to force compiler to keep.
volatile unsigned short sdmy=0; // for code critical section sdmy must not be optimised out
volatile unsigned int udmy=0; // for code critical section sdmy must not be optimised out
volatile unsigned int st_TMR1O; // updated in gate.c
// controls on this code comment out the following to stop using LCD
//#define USE_MY_LCD
//#define USE_LCD
//#define USE_USART
// This macro saves typing a lot of code.
#define REFRESH_7SEG display_str_8seg7(&op[2],dpIdx)
////////////////////////////////////////////////////////////////////////
void init_ports(void) {
ADCON1 = 0x06; // all digital outputs
PORTA = 0;
TRISA = 0xFF; // inputs
PORTB = 0;
TRISB = 0; // out
PORTC = 0x01; // b0 = 1 for 7seg
TRISC = 0x81; // B7 = i/p for USART, RC0 T1CKI-Timer1 i/p.
PORTD = 0;
TRISD = 0; // out
PORTE = 0;
TRISE = 0; // out
}
////////////////////////////////////////////////////////////////////////
// Start here
//
void main() org 440 {
char op[12] ; // Display string for seven segment display
unsigned short dpIdx=20 ; // Decimal point index into seven segment.
unsigned int i ; // loop counter
unsigned short st_TMR1L ; // Store Timer 1 low byte (after calced).
unsigned short st_TMR1H ; // store Timer 1 high byte time.
unsigned short refresh ; // refresh display interval count (during calcs).
unsigned long df = 0 ; // dispFlay frequency value to use.
unsigned short blinkc=0 ; // blink counter
#ifdef USE_LCD
char lcdop[4];
#endif
#ifdef USE_MY_LCD
char lcdop[4];
#endif
init_ports();
init_str_8seg7();
#ifdef USE_USART
USART_Init(2400);
#endif // USE_USART
// Timer 1
// prescale = 0, oscillator off, timer on, external clock, unsynchronized.
T1CON = (1<<TMR1ON) | (1<<TMR1CS) | (1<<T1SYNC);
// Enable Timer 1 interrupt flag so that the flag is updated
// interrupt not used just its output.
PIE1 = (1<<TMR1IE) ; // TMR1 overflow flag is enabled and can be polled.
// Note: actual interrupts not enabled.
#ifdef USE_MY_LCD
_LCD_init();
_LCD_Cmd(LCD_CLEAR);
_LCD_Cmd(LCD_CURSOR_OFF);
#endif
#ifdef USE_LCD
LCD_Config(&PORTB,2,1,0,7,6,5,4); // RS,E,W,D7..4
LCD_Cmd(LCD_CLEAR);
LCD_Cmd(LCD_CURSOR_OFF);
#endif
for(;;) {
// blink the led on port C.
if (blinkc>0) { // processor alive indicator
setBit(PORTC,2);
} else {
resBit(PORTC,2);
}
blinkc=~blinkc;
////////////////////////////
// Calculate frequency from timer 1
//
if (!(st_TMR1L==0 && st_TMR1H==0 && st_TMR1O==0) ) {
// Fails in 5.0.0.3
// df =( ((unsigned long) st_TMR1L) ) + \
// ( ((unsigned long) st_TMR1H)<<8 ) + \
// ( ((unsigned long) st_TMR1O)<16);
df = (unsigned long) st_TMR1L + (unsigned long) st_TMR1H * 256 + 65536 * (unsigned long) st_TMR1O;
} else {
df = 0;
}
REFRESH_7SEG;
// convert long to the display string.
ulong2bcd_p1(df); // conversion 1st part.
REFRESH_7SEG;
for (i=0;i<7;i++) {
ulong2bcd_process(void); // conversion 2nd part.
REFRESH_7SEG;
}
process_ulong2str(op);
REFRESH_7SEG;
// Initialize ready for next gate time
st_TMR1L = 0;
st_TMR1H = 0;
st_TMR1O = 0;
//////////////////////////
// GATE and REFRESH
//
// TUNE THIS GATE TIME to 1 second.
//
// 1. Tune the gate_loop first in gate.c
// 2. Then tune here (the overall gate time).
//
// 1.Break on
// gate_loop(1000,op);
// 2. reset the stop watch
// 3. step through until landing on statement:
// TMR1L_st = TMR1L;
//
// Check simluation stopwatch result is 1 second.
//
TMR1H = 0; // clear timer1 high count - the timer1 hardware.
TMR1L = 0; // clear timer1 low count - the timer1 hardware.
PIR1 &= ~(1<<TMR1IF); ; // clear Timer1 overflow bit.
//////////////////////////
// Start of gate time
//
gate_loop(1000,op); // op is the seven segment display string
delay_500_us();
delay_100_us();
delay_100_us();
delay_10_us();
delay_10_us();
delay_10_us();
asm {
CLRW
CLRW
CLRW
CLRW
CLRW
}
st_TMR1L = TMR1L; // get counter values before it updates
st_TMR1H = TMR1H;
/// End of gate time
////////////////////
// test for overflow after tune delay
if ( PIR1 & (1<<TMR1IF) ) {
PIR1 &= ~(1<<TMR1IF); // clear the bit.
st_TMR1O += 1; // increase high count.
}
#ifdef USE_MY_LCD
// lots of refresh needed to keep approx 1ms 7seg refresh rate
_LCD_Print(2,1,"FREQ:"); REFRESH_7SEG;
_LCD_Print(2,6,op); REFRESH_7SEG;
_LCD_Print(1,1,"H"); REFRESH_7SEG;
ByteToStr(st_TMR1H,lcdop); REFRESH_7SEG;
_LCD_Print(1,2, lcdop); REFRESH_7SEG;
_LCD_Print(1,9,"L"); REFRESH_7SEG;
ByteToStr(st_TMR1L,lcdop); REFRESH_7SEG;
_LCD_Print(1, 10, lcdop); REFRESH_7SEG;
#endif
#ifdef USE_LCD
// lots of refresh needed to keep approx 1ms 7seg refresh rate
LCD_Out(2,1,"FREQ:"); REFRESH_7SEG;
LCD_Out(2,6,op); REFRESH_7SEG;
LCD_Out(1,1,"H"); REFRESH_7SEG;
ByteToStr(st_TMR1H,lcdop); REFRESH_7SEG;
LCD_Out(1,2, lcdop); REFRESH_7SEG;
LCD_Out(1,9,"L"); REFRESH_7SEG;
ByteToStr(st_TMR1L,lcdop); REFRESH_7SEG;
LCD_Out(1, 10, lcdop); REFRESH_7SEG;
#endif
#ifdef USE_USART
// test shift left in 5.0.0.3
// st_TMR1O=5;
// st_TMR1H=20;
// df = 70 + 21 * 256 + 65536 * st_TMR1O; // OK
// df = 70 + 21 * 256 + st_TMR1O<<16; // fails
// USART_Print("LONG:");
// LongToStr(df,bcd_ascii); // check that df is accurate
// USART_Println(bcd_ascii);
USART_Print("FREQ:");
USART_Println(op);
USART_Print("H:");
ByteToStr(st_TMR1H,op);
USART_Print(op);
USART_Print(" L:");
ByteToStr(st_TMR1L,op);
USART_Print(op);
USART_Print(" O:");
WordToStr(st_TMR1O,op);
USART_Println(op);
#endif // USE_USART
}
}