AT 90S2313 microcontroller based AVR digital counter with Source code

Another cool microcontroller project from jesper. Counter measurer using microcontroller AT 90S2313, you can use ATtiny 2313 to replace it. It could be a simple digital counter count up at 35-40Mhz.The software written in C code.

“It uses only 4 chips – 3 HC TTL’s and an Atmel At90S2313 microcontroller. It has a 5 digit LED display plus one used as a band indicator. Even with the LED display, the current consumption is less than 50 mA. It counts up to at least 52 MHz. I couldn’t find any signal source in the lab that could supply more than 52 MHz, so it may go a bit higher, but the fClock(typ) for the HC590 is about 35-40 MHz, so you shouldn’t really count (no pun intended) on more.”

Schematic

Source Code for counter measurer

/*
Jesper Hansen

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

// 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 0×01
#define SEG_b 0×02
#define SEG_c 0×04
#define SEG_d 0×08
#define SEG_e 0×10
#define SEG_f 0×20
#define SEG_g 0×40
#define SEG_dot 0×80

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;

SIGNAL(SIG_OVERFLOW0) //timer 0 overflow
{
unsigned char a,b;

// reload timer
outp(TI0_L, TCNT0);

// all displays off by setting all commons high
outp(inp(PORTB) | 0×07, 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) | 0×07, 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 volatile(“nop”);
sbi(PORTD,OE_H); // one pulse to latch count
asm volatile(“nop”);
cbi(PORTD,OE_H);
asm volatile(“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 volatile(“nop”);
sbi(PORTD,OE_L); // one pulse to latch count
asm volatile(“nop”);
cbi(PORTD,OE_L);
asm volatile(“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 volatile(“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(0×40,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 *******************************************************************/
/****************************************************************************/

int 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(0×03, 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(0×01,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

}

S:electronicsuite.com


EmoticonEmoticon

Advertisement