⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 counter.c

📁 本文给出了频率计的一般设计方法及软件的如何编码
💻 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 + -