📄 counter.c
字号:
/*
Jesper Hansen <jesperh@telia.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Project: CounterMeasures
40 MHz Frequency Counter
------------------------
CPU : At90S2313
Date: 2001-03-02
Author : Jesper Hansen
Current consumption about 40-45 mA.
Measures to > 50 MHz
*/
#include <io2313v.h>
#include <macros.h>
#include "counter.h"
// PORT D bits
// al counter control bits active low
#define CLEAR PD6
#define OE_H PD5
#define OE_L PD4
// PD3..0 is lower data bus
// PORT B
// PB7..4 is high data bus
// PB3 is OC1 output
// PB2..0 is 74HC138 select bits for display common
// constants/macros
#define F_CPU 4000000 // 4MHz processor
#define CYCLES_PER_US ((F_CPU+500000)/1000000) // cpu cycles per microsecond
// display data
#define SEG_a 0x01
#define SEG_b 0x02
#define SEG_c 0x04
#define SEG_d 0x08
#define SEG_e 0x10
#define SEG_f 0x20
#define SEG_g 0x40
#define SEG_dot 0x80
unsigned char digits[] = {
(SEG_a|SEG_b|SEG_c|SEG_d|SEG_e|SEG_f), // 0
(SEG_b|SEG_c), // 1
(SEG_a|SEG_b|SEG_d|SEG_e|SEG_g), // 2
(SEG_a|SEG_b|SEG_c|SEG_d|SEG_g), // 3
(SEG_b|SEG_c|SEG_c|SEG_f|SEG_g), // 4
(SEG_a|SEG_c|SEG_d|SEG_f|SEG_g), // 5
(SEG_a|SEG_c|SEG_d|SEG_e|SEG_f|SEG_g), // 6
(SEG_a|SEG_b|SEG_c), // 7
(SEG_a|SEG_b|SEG_c|SEG_d|SEG_e|SEG_f|SEG_g), // 8
(SEG_a|SEG_b|SEG_c|SEG_d|SEG_f|SEG_g), // 9
(SEG_a), // mode 0 indicator (Hz)
(SEG_g), // mode 1 indicator (kHz)
(SEG_d), // mode 2 indicator (MHz)
};
/****************************************************************************/
// timer 0 interrupt handles multiplex and refresh of the displays
// timer is clocked at 62500 Hz
#define TI0_L (256-125) // 500 Hz -> 2 mS
volatile unsigned char active_led = 0;
volatile unsigned long led_value = 0; // four BCD nibbles
volatile unsigned char decimal_point = 0;
volatile unsigned char mode_setting = 0;
#pragma interrupt_handler timer0_ovf_isr:7
void timer0_ovf_isr(void) //timer 0 overflow
{
unsigned char a,b;
// reload timer
outp(TI0_L, TCNT0);
// all displays off by setting all commons high
outp(inp(PORTB) | 0x07, PORTB);
if (active_led == 5)
{
b = digits[10 + mode_setting];
}
else
{
a = led_value >> (( 4 - active_led ) * 4);
b = digits[a & 0x0f];
if (decimal_point == (4 - active_led) )
b |= SEG_dot;
}
a = b & 0xf0; // hi part
b = b & 0x0f; // lo part
// set digit data on port
outp( (inp(PORTB) & 0x0f) | a, PORTB); // high part
outp( (inp(PORTD) & 0xf0) | b, PORTD); // low part
// set common
outp( (inp(PORTB) & 0xf8) | active_led, PORTB);
active_led = (active_led+1) % 6;
}
/****************************************************************************/
/* helpers ****************************************************************/
/****************************************************************************/
void delay(unsigned short us)
{
unsigned short delay_loops;
register unsigned short i;
delay_loops = (us+3)/5*CYCLES_PER_US; // +3 for rounding up (dirty)
// one loop takes 5 cpu cycles
for (i=0; i < delay_loops; i++) {};
}
//
// read 16 bit counter value
//
unsigned int read_counters(void)
{
unsigned int counter_value;
// stop display refresh while reading counters
cli();
// turn off all segments
outp(inp(PORTB) | 0x07, PORTB);
// set high B port to input
outp(0x0f,DDRB);
// set low D port to input
outp(0xf0,DDRD);
// activate OE_H
cbi(PORTD,OE_H);
asm ("nop");
sbi(PORTD,OE_H); // one pulse to latch count
asm("nop");
cbi(PORTD,OE_H);
asm ("nop");
// read hi
counter_value = (inp(PINB) & 0xf0);
// read lo
counter_value |= (inp(PIND) & 0x0f);
// deactivate OE_H
sbi(PORTD,OE_H);
counter_value <<= 8;
// activate OE_L
cbi(PORTD,OE_L);
asm("nop");
sbi(PORTD,OE_L); // one pulse to latch count
asm ("nop");
cbi(PORTD,OE_L);
asm ("nop");
// read hi
counter_value |= (inp(PINB) & 0xf0);
// read lo
counter_value |= (inp(PIND) & 0x0f);
// deactivate OE_L
sbi(PORTD,OE_L);
// set B port back to output
outp(0xff,DDRB);
// set D port back to output
outp(0xff,DDRD);
// re-enable display refresh
sei();
return counter_value;
}
//
// do a capture
//
void capture(unsigned int compare)
{
cbi(PORTD,CLEAR); // clear external counters
asm ("nop");
sbi(PORTD,CLEAR); // remove clear
outp(0,TCNT1H); // clear timer
outp(0,TCNT1L);
outp(compare >> 8,OCR1H); // set the compare1 register to the
outp(compare,OCR1L); // required value
outp(0x40,TCCR1A); // set OC1 bit to toggle on compare
sbi(TIFR,OCF1A); // clear overflov/compare flags
if (compare == 15625)
outp(0x0C,TCCR1B); // start with fClk/256 (15625 Hz) and compare clear
else
outp(0x0A,TCCR1B); // start with fClk/8 (500 kHz) and compare clear
while ( ! (unsigned char) ( inp(TIFR) & BV(OCF1A)) ); // wait for bit
sbi(TIFR,OCF1A); // clear flags
// counter input now enabled
// for the specified time
while ( ! (unsigned char) ( inp(TIFR) & BV(OCF1A)) ); // wait again for bit
outp(0,TCCR1B); // stop timer
// counter input disabled
}
/****************************************************************************/
/* main *******************************************************************/
/****************************************************************************/
void main(void)
{
int i,j;
unsigned char dp,ms;
unsigned long lv;
unsigned int count;
// set all PORTB as outputs
outp(0xff,DDRB);
// set all bits hi
outp(0xff,PORTB);
// set all PORTD as outputs
outp(0xff,DDRD);
// set all bits hi
outp(0xff,PORTD);
// setup timer 0
outp(0x03, TCCR0); // prescaler f/64 tPeriod = 1/62500 Hz -> 16 uS
// enable timer 0 interrupt
sbi(TIMSK, TOIE0);
// start things running
sei();
/*
compare values at fclk/8 (500 kHz, 2 uS) :
500 = 1 mS
5000 = 10 mS
50000 = 100 mS
at fclk/256 (15.625 kHz, 64 uS) :
15625 = 1 S
*/
// first make sure the OC1 pin is in a controlled state
// we want it to be HIGH initially
// There's no way to set/clear it directly, but it can be forced to
// a defined state by a compare match, se by setting a low compare value
// and start the timer, it can be forced into set state
outp(0,TCNT1H); // clear timer
outp(0,TCNT1L);
outp(0,OCR1H); // set compare to 200
outp(200,OCR1L);
outp(0xC0,TCCR1A); // set OC1 bit to set on compare
// start timer and wait for one compare match
outp(0x01,TCCR1B); // start with fClk/1 (4 MHz)
while ( ! (unsigned char) ( inp(TIFR) & BV(OCF1A)) ); // wait for bit
sbi(TIFR,OCF1A); // clear flags
outp(0,TCCR1B); // stop timer
// compare bit no HI, start
// doing some useful work
while (1)
{
// try a capture at min gate
capture(500); // 1 mS
// get the data
count = read_counters();
dp = 3; // decimal point
ms = 2; // indicate MHz
if (count < 4096) // less than 4.096 MHz
{
// try a capture at next gate value
capture(5000); // 10 mS
// get the data
count = read_counters();
dp = 4; // decimal point
ms = 2; // indicate MHz
if (count < 4096) // less than 409.6 kHz
{
// try a capture at next gate value
capture(50000); // 100 mS
// get the data
count = read_counters();
dp = 3; // decimal point
ms = 1; // indicate kHz
if (count < 4096) // less than 40.96 kHz
{
// try a capture at next gate value
capture(15625); // 1 S
// get the data
count = read_counters();
dp = 0; // decimal point
ms = 0; // indicate Hz
}
}
}
// convert BINARY counter_value (int) to BCD in led_value (long)
lv = 0;
for (j=0;j<8;j++)
{
i = count % 10;
lv >>= 4;
lv |= ((unsigned long)i << 28);
count /= 10;
}
// set display variables
decimal_point = dp;
mode_setting = ms;
led_value = lv;
} // loop
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -